wizard.py 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105
  1. """!
  2. @package location_wizard.wizard
  3. @brief Location wizard - creates a new GRASS Location. User can choose
  4. from multiple methods.
  5. Classes:
  6. - wizard::TitledPage
  7. - wizard::DatabasePage
  8. - wizard::CoordinateSystemPage
  9. - wizard::ProjectionsPage
  10. - wizard::ItemList
  11. - wizard::ProjParamsPage
  12. - wizard::DatumPage
  13. - wizard::EllipsePage
  14. - wizard::GeoreferencedFilePage
  15. - wizard::WKTPage
  16. - wizard::EPSGPage
  17. - wizard::CustomPage
  18. - wizard::SummaryPage
  19. - wizard::LocationWizard
  20. (C) 2007-2011 by the GRASS Development Team
  21. This program is free software under the GNU General Public License
  22. (>=v2). Read the file COPYING that comes with GRASS for details.
  23. @author Michael Barton
  24. @author Jachym Cepicky
  25. @author Martin Landa <landa.martin gmail.com>
  26. """
  27. import os
  28. import locale
  29. import wx
  30. import wx.lib.mixins.listctrl as listmix
  31. import wx.wizard as wiz
  32. import wx.lib.scrolledpanel as scrolled
  33. from core import globalvar
  34. from core import utils
  35. from core.gcmd import RunCommand, GError, GMessage, GWarning
  36. from location_wizard.base import BaseClass
  37. from location_wizard.dialogs import RegionDef, SelectTransformDialog
  38. from grass.script import core as grass
  39. global coordsys
  40. global north
  41. global south
  42. global east
  43. global west
  44. global resolution
  45. global wizerror
  46. global translist
  47. class TitledPage(BaseClass, wiz.WizardPageSimple):
  48. """!Class to make wizard pages. Generic methods to make labels,
  49. text entries, and buttons.
  50. """
  51. def __init__(self, parent, title):
  52. self.page = wiz.WizardPageSimple.__init__(self, parent)
  53. # page title
  54. self.title = wx.StaticText(parent = self, id = wx.ID_ANY, label = title)
  55. self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
  56. # main sizers
  57. self.pagesizer = wx.BoxSizer(wx.VERTICAL)
  58. self.sizer = wx.GridBagSizer(vgap = 0, hgap = 0)
  59. def DoLayout(self):
  60. """!Do page layout"""
  61. self.pagesizer.Add(item = self.title, proportion = 0,
  62. flag = wx.ALIGN_CENTRE | wx.ALL,
  63. border = 5)
  64. self.pagesizer.Add(item = wx.StaticLine(self, -1), proportion = 0,
  65. flag = wx.EXPAND | wx.ALL,
  66. border = 0)
  67. self.pagesizer.Add(item = self.sizer, proportion = 1,
  68. flag = wx.EXPAND)
  69. self.SetAutoLayout(True)
  70. self.SetSizer(self.pagesizer)
  71. self.Layout()
  72. class DatabasePage(TitledPage):
  73. """!Wizard page for setting GIS data directory and location name"""
  74. def __init__(self, wizard, parent, grassdatabase):
  75. TitledPage.__init__(self, wizard, _("Define GRASS Database and Location Name"))
  76. self.grassdatabase = grassdatabase
  77. self.location = ''
  78. self.locTitle = ''
  79. # buttons
  80. self.bbrowse = self.MakeButton(_("Browse"))
  81. # text controls
  82. self.tgisdbase = self.MakeTextCtrl(grassdatabase, size = (300, -1))
  83. self.tlocation = self.MakeTextCtrl("newLocation", size = (300, -1))
  84. self.tlocTitle = self.MakeTextCtrl(size = (400, -1))
  85. # layout
  86. self.sizer.AddGrowableCol(3)
  87. self.sizer.Add(item = self.MakeLabel(_("GIS Data Directory:")),
  88. flag = wx.ALIGN_RIGHT |
  89. wx.ALIGN_CENTER_VERTICAL |
  90. wx.ALL, border = 5,
  91. pos = (1, 1))
  92. self.sizer.Add(item = self.tgisdbase,
  93. flag = wx.ALIGN_LEFT |
  94. wx.ALIGN_CENTER_VERTICAL |
  95. wx.ALL, border = 5,
  96. pos = (1, 2))
  97. self.sizer.Add(item = self.bbrowse,
  98. flag = wx.ALIGN_LEFT |
  99. wx.ALIGN_CENTER_VERTICAL |
  100. wx.ALL, border = 5,
  101. pos = (1, 3))
  102. self.sizer.Add(item = self.MakeLabel("%s:" % _("Project Location")),
  103. flag = wx.ALIGN_RIGHT |
  104. wx.ALIGN_CENTER_VERTICAL |
  105. wx.ALL, border = 5,
  106. pos = (2, 1))
  107. self.sizer.Add(item = self.tlocation,
  108. flag = wx.ALIGN_LEFT |
  109. wx.ALIGN_CENTER_VERTICAL |
  110. wx.ALL, border = 5,
  111. pos = (2, 2))
  112. self.sizer.Add(item = self.MakeLabel("%s:" % _("Location Title")),
  113. flag = wx.ALIGN_RIGHT |
  114. wx.ALIGN_TOP | wx.ALIGN_CENTER_VERTICAL |
  115. wx.ALL, border = 5,
  116. pos = (3, 1))
  117. self.sizer.Add(item = self.tlocTitle,
  118. flag = wx.ALIGN_LEFT |
  119. wx.ALIGN_CENTER_VERTICAL |
  120. wx.ALL, border = 5,
  121. pos = (3, 2), span = (1, 2))
  122. # bindings
  123. self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.bbrowse)
  124. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  125. self.tgisdbase.Bind(wx.EVT_TEXT, self.OnChangeName)
  126. self.tlocation.Bind(wx.EVT_TEXT, self.OnChangeName)
  127. def OnChangeName(self, event):
  128. """!Name for new location was changed"""
  129. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  130. if len(event.GetString()) > 0:
  131. if not nextButton.IsEnabled():
  132. nextButton.Enable()
  133. else:
  134. nextButton.Disable()
  135. event.Skip()
  136. def OnBrowse(self, event):
  137. """!Choose GRASS data directory"""
  138. dlg = wx.DirDialog(self, _("Choose GRASS data directory:"),
  139. os.getcwd(), wx.DD_DEFAULT_STYLE)
  140. if dlg.ShowModal() == wx.ID_OK:
  141. self.grassdatabase = dlg.GetPath()
  142. self.tgisdbase.SetValue(self.grassdatabase)
  143. dlg.Destroy()
  144. def OnPageChanging(self, event = None):
  145. error = None
  146. if os.path.isdir(os.path.join(self.tgisdbase.GetValue(), self.tlocation.GetValue())):
  147. error = _("Location already exists in GRASS Database.")
  148. if error:
  149. GError(parent = self,
  150. message="%s <%s>.%s%s" % (_("Unable to create location"),
  151. str(self.tlocation.GetValue()),
  152. os.linesep,
  153. error))
  154. event.Veto()
  155. return
  156. self.location = self.tlocation.GetValue()
  157. self.grassdatabase = self.tgisdbase.GetValue()
  158. self.locTitle = self.tlocTitle.GetValue()
  159. if os.linesep in self.locTitle or \
  160. len(self.locTitle) > 255:
  161. GWarning(parent = self,
  162. message = _("Title of the location is limited only to one line and "
  163. "256 characters. The rest of the text will be ignored."))
  164. self.locTitle = self.locTitle.split(os.linesep)[0][:255]
  165. class CoordinateSystemPage(TitledPage):
  166. """!Wizard page for choosing method for location creation"""
  167. def __init__(self, wizard, parent):
  168. TitledPage.__init__(self, wizard, _("Choose method for creating a new location"))
  169. self.parent = parent
  170. global coordsys
  171. # toggles
  172. self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  173. label = _("Select coordinate system parameters from a list"),
  174. style = wx.RB_GROUP)
  175. self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  176. label = _("Select EPSG code of spatial reference system"))
  177. self.radio3 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  178. label = _("Read projection and datum terms from a "
  179. "georeferenced data file"))
  180. self.radio4 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  181. label = _("Read projection and datum terms from a "
  182. "WKT or PRJ file"))
  183. self.radio5 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  184. label = _("Specify projection and datum terms using custom "
  185. "PROJ.4 parameters"))
  186. self.radio6 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  187. label = _("Create a generic Cartesian coordinate system (XY)"))
  188. # layout
  189. self.sizer.AddGrowableCol(1)
  190. self.sizer.SetVGap(10)
  191. self.sizer.Add(item = self.radio1,
  192. flag = wx.ALIGN_LEFT, pos = (1, 1))
  193. self.sizer.Add(item = self.radio2,
  194. flag = wx.ALIGN_LEFT, pos = (2, 1))
  195. self.sizer.Add(item = self.radio3,
  196. flag = wx.ALIGN_LEFT, pos = (3, 1))
  197. self.sizer.Add(item = self.radio4,
  198. flag = wx.ALIGN_LEFT, pos = (4, 1))
  199. self.sizer.Add(item = self.radio5,
  200. flag = wx.ALIGN_LEFT, pos = (5, 1))
  201. self.sizer.Add(item = self.radio6,
  202. flag = wx.ALIGN_LEFT, pos = (6, 1))
  203. # bindings
  204. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
  205. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
  206. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio3.GetId())
  207. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio4.GetId())
  208. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio5.GetId())
  209. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio6.GetId())
  210. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  211. def OnEnterPage(self, event):
  212. global coordsys
  213. if not coordsys:
  214. coordsys = "proj"
  215. self.radio1.SetValue(True)
  216. else:
  217. if coordsys == 'proj':
  218. self.radio1.SetValue(True)
  219. if coordsys == "epsg":
  220. self.radio2.SetValue(True)
  221. if coordsys == "file":
  222. self.radio3.SetValue(True)
  223. if coordsys == "wkt":
  224. self.radio4.SetValue(True)
  225. if coordsys == "custom":
  226. self.radio5.SetValue(True)
  227. if coordsys == "xy":
  228. self.radio6.SetValue(True)
  229. if event.GetDirection():
  230. if coordsys == 'proj':
  231. self.SetNext(self.parent.projpage)
  232. self.parent.sumpage.SetPrev(self.parent.datumpage)
  233. if coordsys == "epsg":
  234. self.SetNext(self.parent.epsgpage)
  235. self.parent.sumpage.SetPrev(self.parent.epsgpage)
  236. if coordsys == "file":
  237. self.SetNext(self.parent.filepage)
  238. self.parent.sumpage.SetPrev(self.parent.filepage)
  239. if coordsys == "wkt":
  240. self.SetNext(self.parent.wktpage)
  241. self.parent.sumpage.SetPrev(self.parent.wktpage)
  242. if coordsys == "custom":
  243. self.SetNext(self.parent.custompage)
  244. self.parent.sumpage.SetPrev(self.parent.custompage)
  245. if coordsys == "xy":
  246. self.SetNext(self.parent.sumpage)
  247. self.parent.sumpage.SetPrev(self.parent.csystemspage)
  248. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  249. wx.FindWindowById(wx.ID_FORWARD).Enable()
  250. def SetVal(self, event):
  251. """!Choose method"""
  252. global coordsys
  253. if event.GetId() == self.radio1.GetId():
  254. coordsys = "proj"
  255. self.SetNext(self.parent.projpage)
  256. self.parent.sumpage.SetPrev(self.parent.datumpage)
  257. elif event.GetId() == self.radio2.GetId():
  258. coordsys = "epsg"
  259. self.SetNext(self.parent.epsgpage)
  260. self.parent.sumpage.SetPrev(self.parent.epsgpage)
  261. elif event.GetId() == self.radio3.GetId():
  262. coordsys = "file"
  263. self.SetNext(self.parent.filepage)
  264. self.parent.sumpage.SetPrev(self.parent.filepage)
  265. elif event.GetId() == self.radio4.GetId():
  266. coordsys = "wkt"
  267. self.SetNext(self.parent.wktpage)
  268. self.parent.sumpage.SetPrev(self.parent.wktpage)
  269. elif event.GetId() == self.radio5.GetId():
  270. coordsys = "custom"
  271. self.SetNext(self.parent.custompage)
  272. self.parent.sumpage.SetPrev(self.parent.custompage)
  273. elif event.GetId() == self.radio6.GetId():
  274. coordsys = "xy"
  275. self.SetNext(self.parent.sumpage)
  276. self.parent.sumpage.SetPrev(self.parent.csystemspage)
  277. class ProjectionsPage(TitledPage):
  278. """!Wizard page for selecting projection (select coordinate system option)"""
  279. def __init__(self, wizard, parent):
  280. TitledPage.__init__(self, wizard, _("Choose projection"))
  281. self.parent = parent
  282. self.proj = ''
  283. self.projdesc = ''
  284. self.p4proj = ''
  285. # text input
  286. self.tproj = self.MakeTextCtrl("", size = (200,-1))
  287. # search box
  288. self.searchb = wx.SearchCtrl(self, size = (200,-1),
  289. style = wx.TE_PROCESS_ENTER)
  290. # projection list
  291. self.projlist = ItemList(self, data = self.parent.projdesc.items(),
  292. columns = [_('Code'), _('Description')])
  293. self.projlist.resizeLastColumn(30)
  294. # layout
  295. self.sizer.AddGrowableCol(3)
  296. self.sizer.Add(item = self.MakeLabel(_("Projection code:")),
  297. flag = wx.ALIGN_LEFT |
  298. wx.ALIGN_CENTER_VERTICAL |
  299. wx.ALL, border = 5, pos = (1, 1))
  300. self.sizer.Add(item = self.tproj,
  301. flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
  302. border = 5, pos = (1, 2))
  303. self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
  304. flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  305. border = 5, pos = (2, 1))
  306. self.sizer.Add(item = self.searchb,
  307. flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
  308. border = 5, pos = (2, 2))
  309. self.sizer.AddGrowableRow(3)
  310. self.sizer.Add(item = self.projlist,
  311. flag = wx.EXPAND |
  312. wx.ALIGN_LEFT |
  313. wx.ALL, border = 5, pos = (3, 1), span = (1, 3))
  314. # events
  315. self.tproj.Bind(wx.EVT_TEXT, self.OnText)
  316. self.tproj.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  317. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  318. self.projlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  319. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  320. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  321. def OnPageChanging(self,event):
  322. if event.GetDirection() and self.proj not in self.parent.projections.keys():
  323. event.Veto()
  324. def OnText(self, event):
  325. """!Projection name changed"""
  326. self.proj = event.GetString().lower()
  327. self.p4proj = ''
  328. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  329. if self.proj not in self.parent.projections.keys() and nextButton.IsEnabled():
  330. nextButton.Enable(False)
  331. if self.proj in self.parent.projections.keys():
  332. if self.proj == 'stp':
  333. wx.MessageBox('Currently State Plane projections must be selected using the '
  334. 'text-based setup (g.setproj), or entered by EPSG code or '
  335. 'custom PROJ.4 terms.',
  336. 'Warning', wx.ICON_WARNING)
  337. self.proj = ''
  338. self.tproj.SetValue(self.proj)
  339. nextButton.Enable(False)
  340. return
  341. elif self.proj.lower() == 'll':
  342. self.p4proj = '+proj=longlat'
  343. else:
  344. self.p4proj = '+proj=' + self.proj.lower()
  345. self.projdesc = self.parent.projections[self.proj][0]
  346. nextButton.Enable()
  347. def OnEnterPage(self, event):
  348. if len(self.proj) == 0:
  349. # disable 'next' button by default
  350. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  351. else:
  352. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  353. event.Skip()
  354. def OnSearch(self, event):
  355. """!Search projection by desc"""
  356. str = event.GetString()
  357. try:
  358. self.proj, self.projdesc = self.projlist.Search(index = [0,1], pattern = event.GetString())
  359. except:
  360. self.proj = self.projdesc = ''
  361. event.Skip()
  362. def OnItemSelected(self, event):
  363. """!Projection selected"""
  364. index = event.m_itemIndex
  365. # set values
  366. self.proj = self.projlist.GetItem(index, 0).GetText().lower()
  367. self.tproj.SetValue(self.proj)
  368. event.Skip()
  369. class ItemList(wx.ListCtrl,
  370. listmix.ListCtrlAutoWidthMixin,
  371. listmix.ColumnSorterMixin):
  372. """!Generic list (for projections, ellipsoids, etc.)"""
  373. def __init__(self, parent, columns, data = None):
  374. wx.ListCtrl.__init__(self, parent = parent, id = wx.ID_ANY,
  375. style = wx.LC_REPORT |
  376. wx.LC_VIRTUAL |
  377. wx.LC_HRULES |
  378. wx.LC_VRULES |
  379. wx.LC_SINGLE_SEL |
  380. wx.LC_SORT_ASCENDING, size = (550, 125))
  381. # original data or None
  382. self.sourceData = data
  383. #
  384. # insert columns
  385. #
  386. i = 0
  387. for column in columns:
  388. self.InsertColumn(i, column)
  389. i += 1
  390. if self.sourceData:
  391. self.Populate()
  392. for i in range(self.GetColumnCount()):
  393. self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
  394. if self.GetColumnWidth(i) < 80:
  395. self.SetColumnWidth(i, 80)
  396. #
  397. # listmix
  398. #
  399. listmix.ListCtrlAutoWidthMixin.__init__(self)
  400. listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())
  401. #
  402. # add some attributes
  403. #
  404. self.attr1 = wx.ListItemAttr()
  405. self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
  406. self.attr2 = wx.ListItemAttr()
  407. self.attr2.SetBackgroundColour("white")
  408. self.il = wx.ImageList(16, 16)
  409. self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR,
  410. (16,16)))
  411. self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
  412. (16,16)))
  413. self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
  414. #
  415. # sort by first column
  416. #
  417. if self.sourceData:
  418. self.SortListItems(col = 0, ascending = True)
  419. #
  420. # bindings
  421. #
  422. self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick)
  423. def Populate(self, data = None, update = False):
  424. """!Populate list"""
  425. self.itemDataMap = {}
  426. self.itemIndexMap = []
  427. if data is None:
  428. data = self.sourceData
  429. elif update:
  430. self.sourceData = data
  431. try:
  432. data.sort()
  433. self.DeleteAllItems()
  434. row = 0
  435. for value in data:
  436. self.itemDataMap[row] = [value[0]]
  437. for i in range(1, len(value)):
  438. self.itemDataMap[row].append(value[i])
  439. self.itemIndexMap.append(row)
  440. row += 1
  441. self.SetItemCount(row)
  442. # set column width
  443. self.SetColumnWidth(0, 80)
  444. self.SetColumnWidth(1, 300)
  445. self.SendSizeEvent()
  446. except StandardError, e:
  447. wx.MessageBox(parent = self,
  448. message = _("Unable to read list: %s") % e,
  449. caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
  450. def OnColumnClick(self, event):
  451. """!Sort by column"""
  452. self._col = event.GetColumn()
  453. # remove duplicated arrow symbol from column header
  454. # FIXME: should be done automatically
  455. info = wx.ListItem()
  456. info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
  457. info.m_image = -1
  458. for column in range(self.GetColumnCount()):
  459. info.m_text = self.GetColumn(column).GetText()
  460. self.SetColumn(column, info)
  461. event.Skip()
  462. def GetSortImages(self):
  463. """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
  464. return (self.sm_dn, self.sm_up)
  465. def OnGetItemText(self, item, col):
  466. """!Get item text"""
  467. index = self.itemIndexMap[item]
  468. s = str(self.itemDataMap[index][col])
  469. return s
  470. def OnGetItemAttr(self, item):
  471. """!Get item attributes"""
  472. index = self.itemIndexMap[item]
  473. if ( index % 2) == 0:
  474. return self.attr2
  475. else:
  476. return self.attr1
  477. def SortItems(self, sorter = cmp):
  478. """!Sort items"""
  479. items = list(self.itemDataMap.keys())
  480. items.sort(self.Sorter)
  481. self.itemIndexMap = items
  482. # redraw the list
  483. self.Refresh()
  484. def Sorter(self, key1, key2):
  485. colName = self.GetColumn(self._col).GetText()
  486. ascending = self._colSortFlag[self._col]
  487. # convert always string
  488. item1 = self.itemDataMap[key1][self._col]
  489. item2 = self.itemDataMap[key2][self._col]
  490. if type(item1) == type('') or type(item2) == type(''):
  491. cmpVal = locale.strcoll(str(item1), str(item2))
  492. else:
  493. cmpVal = cmp(item1, item2)
  494. # If the items are equal then pick something else to make the sort value unique
  495. if cmpVal == 0:
  496. cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
  497. if ascending:
  498. return cmpVal
  499. else:
  500. return -cmpVal
  501. def GetListCtrl(self):
  502. """!Used by listmix.ColumnSorterMixin"""
  503. return self
  504. def Search (self, index, pattern):
  505. """!Search projection by description
  506. Return first found item or None
  507. """
  508. if pattern == '':
  509. self.Populate(self.sourceData)
  510. return []
  511. data = []
  512. pattern = pattern.lower()
  513. for i in range(len(self.sourceData)):
  514. for idx in index:
  515. try:
  516. value = str(self.sourceData[i][idx]).lower()
  517. if pattern in value:
  518. data.append(self.sourceData[i])
  519. break
  520. except UnicodeDecodeError:
  521. # osgeo4w problem (should be fixed)
  522. pass
  523. self.Populate(data)
  524. if len(data) > 0:
  525. return data[0]
  526. else:
  527. return []
  528. class ProjParamsPage(TitledPage):
  529. """!Wizard page for selecting method of setting coordinate system
  530. parameters (select coordinate system option)
  531. """
  532. def __init__(self, wizard, parent):
  533. TitledPage.__init__(self, wizard, _("Choose projection parameters"))
  534. global coordsys
  535. self.parent = parent
  536. self.panel = None
  537. self.prjParamSizer = None
  538. self.pparam = dict()
  539. self.p4projparams = ''
  540. self.projdesc = ''
  541. self.sizer.AddGrowableCol(1)
  542. self.sizer.AddGrowableRow(1)
  543. radioSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  544. label = " %s " % _("Select datum or ellipsoid (next page)"))
  545. radioSBSizer = wx.StaticBoxSizer(radioSBox)
  546. self.sizer.Add(item = radioSBSizer, pos = (0, 1),
  547. flag = wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border = 10)
  548. self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  549. label = _("Datum with associated ellipsoid"),
  550. style = wx.RB_GROUP)
  551. self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  552. label = _("Ellipsoid only"))
  553. # default button setting
  554. if self.radio1.GetValue() == False and self.radio2.GetValue() == False:
  555. self.radio1.SetValue(True)
  556. self.SetNext(self.parent.datumpage)
  557. # self.parent.sumpage.SetPrev(self.parent.datumpage)
  558. radioSBSizer.Add(item = self.radio1,
  559. flag = wx.ALIGN_LEFT | wx.RIGHT, border = 20)
  560. radioSBSizer.Add(item = self.radio2,
  561. flag = wx.ALIGN_LEFT)
  562. # bindings
  563. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
  564. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
  565. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange)
  566. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  567. def OnParamEntry(self, event):
  568. """!Parameter value changed"""
  569. id = event.GetId()
  570. val = event.GetString()
  571. if id not in self.pparam:
  572. event.Skip()
  573. return
  574. param = self.pparam[id]
  575. win = self.FindWindowById(id)
  576. if param['type'] == 'zone':
  577. val = event.GetInt()
  578. if val < 1:
  579. win.SetValue(1)
  580. elif val > 60:
  581. win.SetValue(60)
  582. if param['type'] == 'bool':
  583. param['value'] = event.GetSelection()
  584. else:
  585. param['value'] = val
  586. event.Skip()
  587. def OnPageChange(self,event=None):
  588. """!Go to next page"""
  589. if event.GetDirection():
  590. self.p4projparams = ''
  591. for id, param in self.pparam.iteritems():
  592. if param['type'] == 'bool':
  593. if param['value'] == False:
  594. continue
  595. else:
  596. self.p4projparams += (' +' + param['proj4'])
  597. else:
  598. if param['value'] is None:
  599. wx.MessageBox(parent = self,
  600. message = _('You must enter a value for %s') % param['desc'],
  601. caption = _('Error'), style = wx.ICON_ERROR | wx.CENTRE)
  602. event.Veto()
  603. else:
  604. self.p4projparams += (' +' + param['proj4'] + '=' + str(param['value']))
  605. def OnEnterPage(self,event):
  606. """!Page entered"""
  607. self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
  608. if self.prjParamSizer is None:
  609. # entering page for the first time
  610. self.paramSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  611. label = _(" Enter parameters for %s projection ") % self.projdesc)
  612. paramSBSizer = wx.StaticBoxSizer(self.paramSBox)
  613. self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
  614. self.panel.SetupScrolling()
  615. self.prjParamSizer = wx.GridBagSizer(vgap = 0, hgap = 0)
  616. self.sizer.Add(item = paramSBSizer, pos = (1, 1),
  617. flag = wx.EXPAND)
  618. paramSBSizer.Add(item = self.panel, proportion = 1,
  619. flag = wx.ALIGN_CENTER | wx.EXPAND)
  620. paramSBSizer.Fit(self.panel)
  621. self.panel.SetSizer(self.prjParamSizer)
  622. if event.GetDirection():
  623. self.prjParamSizer.Clear(True)
  624. self.paramSBox.SetLabel(_(" Enter parameters for %s projection ") % self.projdesc)
  625. self.pparam = dict()
  626. row = 0
  627. for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
  628. # get parameters
  629. id = wx.NewId()
  630. param = self.pparam[id] = { 'type' : self.parent.paramdesc[paramgrp[0]][0],
  631. 'proj4': self.parent.paramdesc[paramgrp[0]][1],
  632. 'desc' : self.parent.paramdesc[paramgrp[0]][2] }
  633. # default values
  634. if param['type'] == 'bool':
  635. param['value'] = 0
  636. elif param['type'] == 'zone':
  637. param['value'] = 30
  638. param['desc'] += ' (1-60)'
  639. else:
  640. param['value'] = paramgrp[2]
  641. label = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = param['desc'],
  642. style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
  643. if param['type'] == 'bool':
  644. win = wx.Choice(parent = self.panel, id = id, size = (100,-1),
  645. choices = [_('No'), _('Yes')])
  646. win.SetSelection(param['value'])
  647. win.Bind(wx.EVT_CHOICE, self.OnParamEntry)
  648. elif param['type'] == 'zone':
  649. win = wx.SpinCtrl(parent = self.panel, id = id,
  650. size = (100, -1),
  651. style = wx.SP_ARROW_KEYS | wx.SP_WRAP,
  652. min = 1, max = 60)
  653. win.SetValue(param['value'])
  654. win.Bind(wx.EVT_SPINCTRL, self.OnParamEntry)
  655. win.Bind(wx.EVT_TEXT, self.OnParamEntry)
  656. else:
  657. win = wx.TextCtrl(parent = self.panel, id = id,
  658. value = param['value'],
  659. size=(100, -1))
  660. win.Bind(wx.EVT_TEXT, self.OnParamEntry)
  661. if paramgrp[1] == 'noask':
  662. win.Enable(False)
  663. self.prjParamSizer.Add(item = label, pos = (row, 1),
  664. flag = wx.ALIGN_RIGHT |
  665. wx.ALIGN_CENTER_VERTICAL |
  666. wx.RIGHT, border = 5)
  667. self.prjParamSizer.Add(item = win, pos = (row, 2),
  668. flag = wx.ALIGN_LEFT |
  669. wx.ALIGN_CENTER_VERTICAL |
  670. wx.LEFT, border = 5)
  671. row += 1
  672. self.panel.SetSize(self.panel.GetBestSize())
  673. self.panel.Layout()
  674. self.Layout()
  675. self.Update()
  676. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  677. wx.FindWindowById(wx.ID_FORWARD).Enable()
  678. event.Skip()
  679. def SetVal(self, event):
  680. """!Set value"""
  681. if event.GetId() == self.radio1.GetId():
  682. self.SetNext(self.parent.datumpage)
  683. self.parent.sumpage.SetPrev(self.parent.datumpage)
  684. elif event.GetId() == self.radio2.GetId():
  685. self.SetNext(self.parent.ellipsepage)
  686. self.parent.sumpage.SetPrev(self.parent.ellipsepage)
  687. class DatumPage(TitledPage):
  688. """!Wizard page for selecting datum (with associated ellipsoid)
  689. and datum transformation parameters (select coordinate system option)
  690. """
  691. def __init__(self, wizard, parent):
  692. TitledPage.__init__(self, wizard, _("Specify geodetic datum"))
  693. self.parent = parent
  694. self.datum = ''
  695. self.datumdesc = ''
  696. self.ellipse = ''
  697. self.datumparams = ''
  698. self.proj4params = ''
  699. # text input
  700. self.tdatum = self.MakeTextCtrl("", size = (200,-1))
  701. # search box
  702. self.searchb = wx.SearchCtrl(self, size = (200,-1),
  703. style = wx.TE_PROCESS_ENTER)
  704. # create list control for datum/elipsoid list
  705. data = []
  706. for key in self.parent.datums.keys():
  707. data.append([key, self.parent.datums[key][0], self.parent.datums[key][1]])
  708. self.datumlist = ItemList(self,
  709. data = data,
  710. columns = [_('Code'), _('Ellipsoid'), _('Description')])
  711. self.datumlist.resizeLastColumn(10)
  712. # layout
  713. self.sizer.AddGrowableCol(4)
  714. self.sizer.Add(item = self.MakeLabel(_("Datum code:")),
  715. flag = wx.ALIGN_LEFT |
  716. wx.ALIGN_CENTER_VERTICAL |
  717. wx.ALL, border = 5, pos = (1, 1))
  718. self.sizer.Add(item = self.tdatum,
  719. flag = wx.ALIGN_LEFT |
  720. wx.ALIGN_CENTER_VERTICAL |
  721. wx.ALL, border = 5, pos = (1, 2))
  722. self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
  723. flag = wx.ALIGN_LEFT |
  724. wx.ALIGN_CENTER_VERTICAL |
  725. wx.ALL, border = 5, pos = (2, 1))
  726. self.sizer.Add(item = self.searchb,
  727. flag = wx.ALIGN_LEFT |
  728. wx.ALIGN_CENTER_VERTICAL |
  729. wx.ALL, border = 5, pos = (2, 2))
  730. self.sizer.AddGrowableRow(3)
  731. self.sizer.Add(item = self.datumlist,
  732. flag = wx.EXPAND |
  733. wx.ALIGN_LEFT |
  734. wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
  735. # events
  736. self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected)
  737. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDSearch)
  738. self.tdatum.Bind(wx.EVT_TEXT, self.OnDText)
  739. self.tdatum.Bind(wx.EVT_TEXT_ENTER, self.OnDText)
  740. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  741. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  742. # do page layout
  743. # self.DoLayout()
  744. def OnPageChanging(self, event):
  745. self.proj4params = ''
  746. proj = self.parent.projpage.p4proj
  747. if event.GetDirection():
  748. if self.datum not in self.parent.datums:
  749. event.Veto()
  750. else:
  751. # check for datum tranforms
  752. # proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
  753. ret = RunCommand('g.proj',
  754. read = True,
  755. proj4 = '%s +datum=%s' % (proj, self.datum),
  756. datumtrans = '-1')
  757. if ret != '':
  758. dtrans = ''
  759. # open a dialog to select datum transform number
  760. dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
  761. if dlg.ShowModal() == wx.ID_OK:
  762. dtrans = dlg.GetTransform()
  763. if dtrans == '':
  764. dlg.Destroy()
  765. event.Veto()
  766. return 'Datum transform is required.'
  767. else:
  768. dlg.Destroy()
  769. event.Veto()
  770. return 'Datum transform is required.'
  771. self.parent.datumtrans = dtrans
  772. self.GetNext().SetPrev(self)
  773. self.parent.ellipsepage.ellipse = self.ellipse
  774. self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  775. def OnEnterPage(self,event):
  776. self.parent.datumtrans = None
  777. if event.GetDirection():
  778. if len(self.datum) == 0:
  779. # disable 'next' button by default when entering from previous page
  780. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  781. else:
  782. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  783. event.Skip()
  784. def OnDText(self, event):
  785. """!Datum code changed"""
  786. self.datum = event.GetString()
  787. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  788. if len(self.datum) == 0 or self.datum not in self.parent.datums:
  789. nextButton.Enable(False)
  790. else:
  791. self.ellipse = self.parent.datums[self.datum][0]
  792. self.datumdesc = self.parent.datums[self.datum][1]
  793. self.datumparams = self.parent.datums[self.datum][2]
  794. try:
  795. self.datumparams.remove('dx=0.0')
  796. except:
  797. pass
  798. try:
  799. self.datumparams.remove('dy=0.0')
  800. except:
  801. pass
  802. try:
  803. self.datumparams.remove('dz=0.0')
  804. except:
  805. pass
  806. nextButton.Enable(True)
  807. self.Update()
  808. event.Skip()
  809. def OnDSearch(self, event):
  810. """!Search geodetic datum by desc"""
  811. str = self.searchb.GetValue()
  812. try:
  813. self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search(index = [0,1,2], pattern = str)
  814. except:
  815. self.datum = self.datumdesc = self.ellipsoid = ''
  816. event.Skip()
  817. def OnDatumSelected(self, event):
  818. """!Datum selected"""
  819. index = event.m_itemIndex
  820. item = event.GetItem()
  821. self.datum = self.datumlist.GetItem(index, 0).GetText()
  822. self.tdatum.SetValue(self.datum)
  823. event.Skip()
  824. class EllipsePage(TitledPage):
  825. """!Wizard page for selecting ellipsoid (select coordinate system option)"""
  826. def __init__(self, wizard, parent):
  827. TitledPage.__init__(self, wizard, _("Specify ellipsoid"))
  828. self.parent = parent
  829. self.ellipse = ''
  830. self.ellipsedesc = ''
  831. self.ellipseparams = ''
  832. self.proj4params = ''
  833. # text input
  834. self.tellipse = self.MakeTextCtrl("", size = (200,-1))
  835. # search box
  836. self.searchb = wx.SearchCtrl(self, size = (200,-1),
  837. style = wx.TE_PROCESS_ENTER)
  838. """
  839. #todo: support for swapping ellipse.table list with ellipse.table.solar.system
  840. # radio buttons
  841. self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  842. label = _("Earth based"),
  843. style = wx.RB_GROUP)
  844. self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
  845. label = _("Planetary bodies"))
  846. """
  847. # create list control for ellipse list
  848. data = []
  849. # extract code, desc
  850. for key in self.parent.ellipsoids.keys():
  851. data.append([key, self.parent.ellipsoids[key][0]])
  852. self.ellipselist = ItemList(self, data = data,
  853. columns = [_('Code'), _('Description')])
  854. self.ellipselist.resizeLastColumn(30)
  855. # layout
  856. self.sizer.AddGrowableCol(4)
  857. self.sizer.Add(item = self.MakeLabel(_("Ellipsoid code:")),
  858. flag = wx.ALIGN_RIGHT |
  859. wx.ALIGN_CENTER_VERTICAL |
  860. wx.ALL, border = 5, pos = (1, 1))
  861. self.sizer.Add(item = self.tellipse,
  862. flag = wx.ALIGN_LEFT |
  863. wx.ALIGN_CENTER_VERTICAL |
  864. wx.ALL, border = 5, pos = (1, 2))
  865. """
  866. self.sizer.Add(item = self.radio1,
  867. flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  868. border = 25, pos = (1, 3))
  869. """
  870. self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
  871. flag = wx.ALIGN_RIGHT |
  872. wx.ALIGN_CENTER_VERTICAL |
  873. wx.ALL, border = 5, pos = (2, 1))
  874. self.sizer.Add(item = self.searchb,
  875. flag = wx.ALIGN_LEFT |
  876. wx.ALIGN_CENTER_VERTICAL |
  877. wx.ALL, border = 5, pos = (2, 2))
  878. """
  879. self.sizer.Add(item = self.radio2,
  880. flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  881. border = 25, pos = (2, 3))
  882. """
  883. self.sizer.AddGrowableRow(3)
  884. self.sizer.Add(item = self.ellipselist,
  885. flag = wx.EXPAND |
  886. wx.ALIGN_LEFT |
  887. wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
  888. # events
  889. self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  890. self.tellipse.Bind(wx.EVT_TEXT, self.OnText)
  891. self.tellipse.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  892. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  893. """
  894. self.radio1.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
  895. self.radio2.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
  896. """
  897. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  898. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  899. def OnEnterPage(self,event):
  900. if len(self.ellipse) == 0:
  901. # disable 'next' button by default
  902. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  903. else:
  904. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  905. """
  906. self.scope = 'earth'
  907. """
  908. event.Skip()
  909. def OnPageChanging(self, event):
  910. if event.GetDirection() and self.ellipse not in self.parent.ellipsoids:
  911. event.Veto()
  912. self.proj4params = ''
  913. self.GetNext().SetPrev(self)
  914. self.parent.datumpage.datumparams = ''
  915. # self.GetNext().SetPrev(self) (???)
  916. def OnText(self, event):
  917. """!Ellipspoid code changed"""
  918. self.ellipse = event.GetString()
  919. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  920. if len(self.ellipse) == 0 or self.ellipse not in self.parent.ellipsoids:
  921. nextButton.Enable(False)
  922. self.ellipsedesc = ''
  923. self.ellipseparams = ''
  924. self.proj4params = ''
  925. elif self.ellipse in self.parent.ellipsoids:
  926. self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0]
  927. self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  928. nextButton.Enable(True)
  929. def OnSearch(self, event):
  930. """!Search ellipsoid by desc"""
  931. try:
  932. self.ellipse, self.ellipsedesc = \
  933. self.ellipselist.Search(index=[0,1], pattern=event.GetString())
  934. self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  935. except:
  936. self.ellipse = self.ellipsedesc = self.ellipseparams = ''
  937. event.Skip()
  938. def OnItemSelected(self,event):
  939. """!Ellipsoid selected"""
  940. index = event.m_itemIndex
  941. item = event.GetItem()
  942. self.ellipse = self.ellipselist.GetItem(index, 0).GetText()
  943. self.tellipse.SetValue(self.ellipse)
  944. event.Skip()
  945. """ FIXME: how best to swap them out?
  946. def SetVal(self, event):
  947. #Choose table to use
  948. if event.GetId() == self.radio1.GetId():
  949. self.scope = 'earth'
  950. data = []
  951. for key in self.parent.ellipsoids.keys():
  952. data.append([key, self.parent.ellipsoids[key][0]])
  953. elif event.GetId() == self.radio2.GetId():
  954. self.scope = 'planetary'
  955. data = []
  956. for key in self.parent.planetary_ellipsoids.keys():
  957. data.append([key, self.parent.planetary_ellipsoids[key][0]])
  958. """
  959. class GeoreferencedFilePage(TitledPage):
  960. """!Wizard page for selecting georeferenced file to use
  961. for setting coordinate system parameters"""
  962. def __init__(self, wizard, parent):
  963. TitledPage.__init__(self, wizard, _("Select georeferenced file"))
  964. self.georeffile = ''
  965. # create controls
  966. self.lfile= self.MakeLabel(_("Georeferenced file:"))
  967. self.tfile = self.MakeTextCtrl(size = (300,-1))
  968. self.bbrowse = self.MakeButton(_("Browse"))
  969. # do layout
  970. self.sizer.AddGrowableCol(3)
  971. self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
  972. wx.ALIGN_CENTRE_VERTICAL |
  973. wx.ALL, border = 5, pos = (1, 1))
  974. self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
  975. wx.ALIGN_CENTRE_VERTICAL |
  976. wx.ALL, border = 5, pos = (1, 2))
  977. self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
  978. wx.ALL, border = 5, pos = (1, 3))
  979. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  980. self.tfile.Bind(wx.EVT_TEXT, self.OnText)
  981. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  982. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  983. # do page layout
  984. # self.DoLayout()
  985. def OnEnterPage(self, event):
  986. if len(self.georeffile) == 0:
  987. # disable 'next' button by default
  988. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  989. else:
  990. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  991. event.Skip()
  992. def OnPageChanging(self, event):
  993. if event.GetDirection() and not os.path.isfile(self.georeffile):
  994. event.Veto()
  995. self.GetNext().SetPrev(self)
  996. event.Skip()
  997. def OnText(self, event):
  998. """!File changed"""
  999. self.georeffile = event.GetString()
  1000. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1001. if len(self.georeffile) > 0 and os.path.isfile(self.georeffile):
  1002. if not nextButton.IsEnabled():
  1003. nextButton.Enable(True)
  1004. else:
  1005. if nextButton.IsEnabled():
  1006. nextButton.Enable(False)
  1007. event.Skip()
  1008. def OnBrowse(self, event):
  1009. """!Choose file"""
  1010. dlg = wx.FileDialog(self,
  1011. _("Select georeferenced file"),
  1012. os.getcwd(), "", "*.*", wx.OPEN)
  1013. if dlg.ShowModal() == wx.ID_OK:
  1014. path = dlg.GetPath()
  1015. self.tfile.SetValue(path)
  1016. dlg.Destroy()
  1017. event.Skip()
  1018. class WKTPage(TitledPage):
  1019. """!Wizard page for selecting WKT file to use
  1020. for setting coordinate system parameters"""
  1021. def __init__(self, wizard, parent):
  1022. TitledPage.__init__(self, wizard, _("Select WKT file"))
  1023. self.wktfile = ''
  1024. # create controls
  1025. self.lfile= self.MakeLabel(_("WKT file:"))
  1026. self.tfile = self.MakeTextCtrl(size = (300,-1))
  1027. self.bbrowse = self.MakeButton(_("Browse"))
  1028. # do layout
  1029. self.sizer.AddGrowableCol(3)
  1030. self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
  1031. wx.ALIGN_CENTRE_VERTICAL |
  1032. wx.ALL, border = 5, pos = (1, 1))
  1033. self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
  1034. wx.ALIGN_CENTRE_VERTICAL |
  1035. wx.ALL, border = 5, pos = (1, 2))
  1036. self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
  1037. wx.ALL, border = 5, pos = (1, 3))
  1038. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  1039. self.tfile.Bind(wx.EVT_TEXT, self.OnText)
  1040. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1041. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1042. def OnEnterPage(self, event):
  1043. if len(self.wktfile) == 0:
  1044. # disable 'next' button by default
  1045. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1046. else:
  1047. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1048. event.Skip()
  1049. def OnPageChanging(self, event):
  1050. if event.GetDirection() and not os.path.isfile(self.wktfile):
  1051. event.Veto()
  1052. self.GetNext().SetPrev(self)
  1053. event.Skip()
  1054. def OnText(self, event):
  1055. """!File changed"""
  1056. self.wktfile = event.GetString()
  1057. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1058. if len(self.wktfile) > 0 and os.path.isfile(self.wktfile):
  1059. if not nextButton.IsEnabled():
  1060. nextButton.Enable(True)
  1061. else:
  1062. if nextButton.IsEnabled():
  1063. nextButton.Enable(False)
  1064. event.Skip()
  1065. def OnBrowse(self, event):
  1066. """!Choose file"""
  1067. dlg = wx.FileDialog(self,
  1068. _("Select WKT file"),
  1069. os.getcwd(), "", "*.*", wx.OPEN)
  1070. if dlg.ShowModal() == wx.ID_OK:
  1071. path = dlg.GetPath()
  1072. self.tfile.SetValue(path)
  1073. dlg.Destroy()
  1074. event.Skip()
  1075. class EPSGPage(TitledPage):
  1076. """!Wizard page for selecting EPSG code for
  1077. setting coordinate system parameters"""
  1078. def __init__(self, wizard, parent):
  1079. TitledPage.__init__(self, wizard, _("Choose EPSG Code"))
  1080. self.parent = parent
  1081. self.epsgCodeDict = {}
  1082. self.epsgcode = None
  1083. self.epsgdesc = ''
  1084. self.epsgparams = ''
  1085. # labels
  1086. self.lfile = self.MakeLabel(_("Path to the EPSG-codes file:"),
  1087. style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  1088. self.lcode = self.MakeLabel(_("EPSG code:"),
  1089. style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  1090. # text input
  1091. epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
  1092. self.tfile = self.MakeTextCtrl(text = epsgdir, size = (200,-1),
  1093. style = wx.TE_PROCESS_ENTER)
  1094. self.tcode = self.MakeTextCtrl(size = (200,-1))
  1095. # buttons
  1096. self.bbrowse = self.MakeButton(_("Browse"))
  1097. # search box
  1098. self.searchb = wx.SearchCtrl(self, size = (200,-1),
  1099. style = wx.TE_PROCESS_ENTER)
  1100. self.epsglist = ItemList(self, data = None,
  1101. columns = [_('Code'), _('Description'), _('Parameters')])
  1102. # layout
  1103. self.sizer.AddGrowableCol(3)
  1104. self.sizer.Add(item = self.lfile,
  1105. flag = wx.ALIGN_LEFT |
  1106. wx.ALIGN_CENTER_VERTICAL |
  1107. wx.ALL, border = 5, pos = (1, 1), span = (1, 2))
  1108. self.sizer.Add(item = self.tfile,
  1109. flag = wx.ALIGN_LEFT |
  1110. wx.ALIGN_CENTER_VERTICAL |
  1111. wx.ALL, border = 5, pos = (1, 3))
  1112. self.sizer.Add(item = self.bbrowse,
  1113. flag = wx.ALIGN_LEFT |
  1114. wx.ALIGN_CENTER_VERTICAL |
  1115. wx.ALL, border = 5, pos = (1, 4))
  1116. self.sizer.Add(item = self.lcode,
  1117. flag = wx.ALIGN_LEFT |
  1118. wx.ALIGN_CENTER_VERTICAL |
  1119. wx.ALL, border = 5, pos = (2, 1), span = (1, 2))
  1120. self.sizer.Add(item = self.tcode,
  1121. flag = wx.ALIGN_LEFT |
  1122. wx.ALIGN_CENTER_VERTICAL |
  1123. wx.ALL, border = 5, pos = (2, 3))
  1124. self.sizer.Add(item = self.searchb,
  1125. flag = wx.ALIGN_LEFT |
  1126. wx.ALIGN_CENTER_VERTICAL |
  1127. wx.ALL, border = 5, pos = (3, 3))
  1128. self.sizer.AddGrowableRow(4)
  1129. self.sizer.Add(item = self.epsglist,
  1130. flag = wx.ALIGN_LEFT | wx.EXPAND, pos = (4, 1),
  1131. span = (1, 4))
  1132. # events
  1133. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  1134. self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes)
  1135. self.tcode.Bind(wx.EVT_TEXT, self.OnText)
  1136. self.tcode.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  1137. self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  1138. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  1139. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1140. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1141. def OnEnterPage(self, event):
  1142. self.parent.datumtrans = None
  1143. if event.GetDirection():
  1144. if not self.epsgcode:
  1145. # disable 'next' button by default
  1146. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1147. else:
  1148. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1149. # load default epsg database file
  1150. self.OnBrowseCodes(None)
  1151. event.Skip()
  1152. def OnPageChanging(self, event):
  1153. if event.GetDirection():
  1154. if not self.epsgcode:
  1155. event.Veto()
  1156. return
  1157. else:
  1158. # check for datum transforms
  1159. ret = RunCommand('g.proj',
  1160. read = True,
  1161. epsg = self.epsgcode,
  1162. datumtrans = '-1')
  1163. if ret != '':
  1164. dtrans = ''
  1165. # open a dialog to select datum transform number
  1166. dlg = SelectTransformDialog(self.parent.parent, transforms = ret)
  1167. if dlg.ShowModal() == wx.ID_OK:
  1168. dtrans = dlg.GetTransform()
  1169. if dtrans == '':
  1170. dlg.Destroy()
  1171. event.Veto()
  1172. return 'Datum transform is required.'
  1173. else:
  1174. dlg.Destroy()
  1175. event.Veto()
  1176. return 'Datum transform is required.'
  1177. self.parent.datumtrans = dtrans
  1178. self.GetNext().SetPrev(self)
  1179. def OnText(self, event):
  1180. self.epsgcode = event.GetString()
  1181. try:
  1182. self.epsgcode = int(self.epsgcode)
  1183. except:
  1184. self.epsgcode = None
  1185. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1186. if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys():
  1187. self.epsgdesc = self.epsgCodeDict[self.epsgcode][0]
  1188. self.epsgparams = self.epsgCodeDict[self.epsgcode][1]
  1189. if not nextButton.IsEnabled():
  1190. nextButton.Enable(True)
  1191. else:
  1192. self.epsgcode = None # not found
  1193. if nextButton.IsEnabled():
  1194. nextButton.Enable(False)
  1195. self.epsgdesc = self.epsgparams = ''
  1196. def OnSearch(self, event):
  1197. value = self.searchb.GetValue()
  1198. if value == '':
  1199. self.epsgcode = None
  1200. self.epsgdesc = self.epsgparams = ''
  1201. self.tcode.SetValue('')
  1202. self.searchb.SetValue('')
  1203. self.OnBrowseCodes(None)
  1204. else:
  1205. try:
  1206. self.epsgcode, self.epsgdesc, self.epsgparams = \
  1207. self.epsglist.Search(index=[0,1,2], pattern=value)
  1208. except (IndexError, ValueError): # -> no item found
  1209. self.epsgcode = None
  1210. self.epsgdesc = self.epsgparams = ''
  1211. self.tcode.SetValue('')
  1212. self.searchb.SetValue('')
  1213. event.Skip()
  1214. def OnBrowse(self, event):
  1215. """!Define path for EPSG code file"""
  1216. path = os.path.dirname(self.tfile.GetValue())
  1217. if not path:
  1218. path = os.getcwd()
  1219. dlg = wx.FileDialog(parent = self, message = _("Choose EPSG codes file"),
  1220. defaultDir = path, defaultFile = "", wildcard = "*", style = wx.OPEN)
  1221. if dlg.ShowModal() == wx.ID_OK:
  1222. path = dlg.GetPath()
  1223. self.tfile.SetValue(path)
  1224. self.OnBrowseCodes(None)
  1225. dlg.Destroy()
  1226. event.Skip()
  1227. def OnItemSelected(self, event):
  1228. """!EPSG code selected from the list"""
  1229. index = event.m_itemIndex
  1230. item = event.GetItem()
  1231. self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText())
  1232. self.epsgdesc = self.epsglist.GetItem(index, 1).GetText()
  1233. self.tcode.SetValue(str(self.epsgcode))
  1234. event.Skip()
  1235. def OnBrowseCodes(self, event, search = None):
  1236. """!Browse EPSG codes"""
  1237. self.epsgCodeDict = utils.ReadEpsgCodes(self.tfile.GetValue())
  1238. if type(self.epsgCodeDict) != dict:
  1239. wx.MessageBox(parent = self,
  1240. message = _("Unable to read EPGS codes: %s") % self.epsgCodeDict,
  1241. caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1242. self.epsglist.Populate(list(), update = True)
  1243. return
  1244. data = list()
  1245. for code, val in self.epsgCodeDict.iteritems():
  1246. if code is not None:
  1247. data.append((code, val[0], val[1]))
  1248. self.epsglist.Populate(data, update = True)
  1249. class CustomPage(TitledPage):
  1250. """!Wizard page for entering custom PROJ.4 string
  1251. for setting coordinate system parameters"""
  1252. def __init__(self, wizard, parent):
  1253. TitledPage.__init__(self, wizard,
  1254. _("Choose method of specifying georeferencing parameters"))
  1255. global coordsys
  1256. self.customstring = ''
  1257. self.parent = parent
  1258. # widgets
  1259. self.text_proj4string = self.MakeTextCtrl(size = (400, 200),
  1260. style = wx.TE_MULTILINE)
  1261. self.label_proj4string = self.MakeLabel(_("Enter PROJ.4 parameters string:"))
  1262. # layout
  1263. self.sizer.AddGrowableCol(2)
  1264. self.sizer.Add(self.label_proj4string,
  1265. flag = wx.ALIGN_LEFT | wx.ALL,
  1266. border = 5, pos = (1, 1))
  1267. self.sizer.AddGrowableRow(2)
  1268. self.sizer.Add(self.text_proj4string,
  1269. flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
  1270. border = 5, pos = (2, 1), span = (1, 2))
  1271. self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring)
  1272. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1273. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1274. def OnEnterPage(self, event):
  1275. if len(self.customstring) == 0:
  1276. # disable 'next' button by default
  1277. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1278. else:
  1279. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1280. def OnPageChanging(self, event):
  1281. if event.GetDirection():
  1282. # check for datum tranforms
  1283. ret, out, err = RunCommand('g.proj',
  1284. read = True, getErrorMsg = True,
  1285. proj4 = self.customstring,
  1286. datumtrans = '-1')
  1287. if ret != 0:
  1288. wx.MessageBox(parent = self,
  1289. message = err,
  1290. caption = _("Error"),
  1291. style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1292. event.Veto()
  1293. return
  1294. if out:
  1295. dtrans = ''
  1296. # open a dialog to select datum transform number
  1297. dlg = SelectTransformDialog(self.parent.parent, transforms = out)
  1298. if dlg.ShowModal() == wx.ID_OK:
  1299. dtrans = dlg.GetTransform()
  1300. if len(dtrans) == 0:
  1301. dlg.Destroy()
  1302. event.Veto()
  1303. return _('Datum transform is required.')
  1304. else:
  1305. dlg.Destroy()
  1306. event.Veto()
  1307. return _('Datum transform is required.')
  1308. self.parent.datumtrans = dtrans
  1309. self.GetNext().SetPrev(self)
  1310. def GetProjstring(self, event):
  1311. """!Change proj string"""
  1312. # TODO: check PROJ.4 syntax
  1313. self.customstring = event.GetString()
  1314. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1315. if len(self.customstring) == 0:
  1316. if nextButton.IsEnabled():
  1317. nextButton.Enable(False)
  1318. else:
  1319. if not nextButton.IsEnabled():
  1320. nextButton.Enable()
  1321. class SummaryPage(TitledPage):
  1322. """!Shows summary result of choosing coordinate system parameters
  1323. prior to creating location"""
  1324. def __init__(self, wizard, parent):
  1325. TitledPage.__init__(self, wizard, _("Summary"))
  1326. self.parent = parent
  1327. self.panelTitle = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
  1328. self.panelProj4string = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
  1329. self.panelProj = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
  1330. # labels
  1331. self.ldatabase = self.MakeLabel()
  1332. self.llocation = self.MakeLabel()
  1333. self.llocTitle = self.MakeLabel(parent = self.panelTitle)
  1334. self.lprojection = self.MakeLabel(parent = self.panelProj)
  1335. self.lproj4string = self.MakeLabel(parent = self.panelProj4string)
  1336. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1337. # do sub-page layout
  1338. self._doLayout()
  1339. def _doLayout(self):
  1340. """!Do page layout"""
  1341. self.sizer.AddGrowableCol(1)
  1342. self.sizer.AddGrowableRow(3, 1)
  1343. self.sizer.AddGrowableRow(4, 1)
  1344. self.sizer.AddGrowableRow(5, 5)
  1345. titleSizer = wx.BoxSizer(wx.VERTICAL)
  1346. titleSizer.Add(item = self.llocTitle, proportion = 1,
  1347. flag = wx.EXPAND | wx.ALL, border = 5)
  1348. self.panelTitle.SetSizer(titleSizer)
  1349. projSizer = wx.BoxSizer(wx.VERTICAL)
  1350. projSizer.Add(item = self.lprojection, proportion = 1,
  1351. flag = wx.EXPAND | wx.ALL, border = 5)
  1352. self.panelProj.SetSizer(projSizer)
  1353. proj4stringSizer = wx.BoxSizer(wx.VERTICAL)
  1354. proj4stringSizer.Add(item = self.lproj4string, proportion = 1,
  1355. flag = wx.EXPAND | wx.ALL, border = 5)
  1356. self.panelProj4string.SetSizer(proj4stringSizer)
  1357. self.panelProj4string.SetupScrolling()
  1358. self.panelProj.SetupScrolling(scroll_y = False)
  1359. self.panelTitle.SetupScrolling(scroll_y = False)
  1360. self.sizer.Add(item = self.MakeLabel(_("GRASS Database:")),
  1361. flag = wx.ALIGN_LEFT | wx.ALL,
  1362. border = 5, pos = (1, 0))
  1363. self.sizer.Add(item = self.ldatabase,
  1364. flag = wx.ALIGN_LEFT | wx.ALL,
  1365. border = 5, pos = (1, 1))
  1366. self.sizer.Add(item = self.MakeLabel(_("Location Name:")),
  1367. flag = wx.ALIGN_LEFT | wx.ALL,
  1368. border = 5, pos = (2, 0))
  1369. self.sizer.Add(item = self.llocation,
  1370. flag = wx.ALIGN_LEFT | wx.ALL,
  1371. border = 5, pos = (2, 1))
  1372. self.sizer.Add(item = self.MakeLabel(_("Location Title:")),
  1373. flag = wx.ALIGN_LEFT | wx.ALL,
  1374. border = 5, pos = (3, 0))
  1375. self.sizer.Add(item = self.panelTitle,
  1376. flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
  1377. border = 0, pos = (3, 1))
  1378. self.sizer.Add(item = self.MakeLabel(_("Projection:")),
  1379. flag = wx.ALIGN_LEFT | wx.ALL,
  1380. border = 5, pos = (4, 0))
  1381. self.sizer.Add(item = self.panelProj,
  1382. flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
  1383. border = 0, pos = (4, 1))
  1384. self.sizer.Add(item = self.MakeLabel(_("PROJ.4 definition:")),
  1385. flag = wx.ALIGN_LEFT | wx.ALL,
  1386. border = 5, pos = (5, 0))
  1387. self.sizer.Add(item = self.panelProj4string,
  1388. flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
  1389. border = 0, pos = (5, 1))
  1390. def OnEnterPage(self, event):
  1391. """!Insert values into text controls for summary of location
  1392. creation options
  1393. """
  1394. database = self.parent.startpage.grassdatabase
  1395. location = self.parent.startpage.location
  1396. proj4string = self.parent.CreateProj4String()
  1397. epsgcode = self.parent.epsgpage.epsgcode
  1398. dtrans = self.parent.datumtrans
  1399. global coordsys
  1400. if coordsys in ('proj', 'epsg'):
  1401. if coordsys == 'proj':
  1402. ret, projlabel, err = RunCommand('g.proj',
  1403. flags = 'jf',
  1404. proj4 = proj4string,
  1405. datumtrans = dtrans,
  1406. location = location,
  1407. getErrorMsg = True,
  1408. read = True)
  1409. elif coordsys == 'epsg':
  1410. ret, projlabel, err = RunCommand('g.proj',
  1411. flags = 'jf',
  1412. epsg = epsgcode,
  1413. datumtrans = dtrans,
  1414. location = location,
  1415. getErrorMsg = True,
  1416. read = True)
  1417. finishButton = wx.FindWindowById(wx.ID_FORWARD)
  1418. if ret == 0:
  1419. self.lproj4string.SetLabel(projlabel.replace(' ', os.linesep))
  1420. finishButton.Enable(True)
  1421. else:
  1422. GError(err, parent = self)
  1423. self.lproj4string.SetLabel('')
  1424. finishButton.Enable(False)
  1425. projdesc = self.parent.projpage.projdesc
  1426. ellipsedesc = self.parent.ellipsepage.ellipsedesc
  1427. datumdesc = self.parent.datumpage.datumdesc
  1428. self.ldatabase.SetLabel(database)
  1429. self.llocation.SetLabel(location)
  1430. self.llocTitle.SetLabel(self.parent.startpage.locTitle)
  1431. label = ''
  1432. if coordsys == 'epsg':
  1433. label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
  1434. elif coordsys == 'file':
  1435. label = 'matches file %s' % self.parent.filepage.georeffile
  1436. self.lproj4string.SetLabel("")
  1437. elif coordsys == 'wkt':
  1438. label = 'matches file %s' % self.parent.wktpage.wktfile
  1439. self.lproj4string.SetLabel("")
  1440. elif coordsys == 'proj':
  1441. label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
  1442. elif coordsys == 'xy':
  1443. label = ('XY coordinate system (not projected).')
  1444. self.lproj4string.SetLabel("")
  1445. elif coordsys == 'custom':
  1446. label = _("custom")
  1447. self.lproj4string.SetLabel(('%s' % self.parent.custompage.customstring.replace(' ', os.linesep)))
  1448. self.lprojection.SetLabel(label)
  1449. def OnFinish(self, event):
  1450. dlg = wx.MessageDialog(parent = self.wizard,
  1451. message = _("Do you want to create GRASS location <%s>?") % location,
  1452. caption = _("Create new location?"),
  1453. style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
  1454. if dlg.ShowModal() == wx.ID_NO:
  1455. dlg.Destroy()
  1456. event.Veto()
  1457. else:
  1458. dlg.Destroy()
  1459. event.Skip()
  1460. class LocationWizard(wx.Object):
  1461. """!Start wizard here and finish wizard here
  1462. """
  1463. def __init__(self, parent, grassdatabase):
  1464. self.__cleanUp()
  1465. global coordsys
  1466. self.parent = parent
  1467. #
  1468. # define wizard image
  1469. #
  1470. imagePath = os.path.join(globalvar.ETCIMGDIR, "loc_wizard_qgis.png")
  1471. wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
  1472. wizbmp = wizbmp.ConvertToBitmap()
  1473. #
  1474. # get georeferencing information from tables in $GISBASE/etc
  1475. #
  1476. self.__readData()
  1477. #
  1478. # datum transform number and list of datum transforms
  1479. #
  1480. self.datumtrans = None
  1481. self.proj4string = ''
  1482. #
  1483. # define wizard pages
  1484. #
  1485. self.wizard = wiz.Wizard(parent, id = wx.ID_ANY, title = _("Define new GRASS Location"),
  1486. bitmap = wizbmp, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
  1487. self.startpage = DatabasePage(self.wizard, self, grassdatabase)
  1488. self.csystemspage = CoordinateSystemPage(self.wizard, self)
  1489. self.projpage = ProjectionsPage(self.wizard, self)
  1490. self.datumpage = DatumPage(self.wizard, self)
  1491. self.paramspage = ProjParamsPage(self.wizard,self)
  1492. self.epsgpage = EPSGPage(self.wizard, self)
  1493. self.filepage = GeoreferencedFilePage(self.wizard, self)
  1494. self.wktpage = WKTPage(self.wizard, self)
  1495. self.ellipsepage = EllipsePage(self.wizard, self)
  1496. self.custompage = CustomPage(self.wizard, self)
  1497. self.sumpage = SummaryPage(self.wizard, self)
  1498. #
  1499. # set the initial order of the pages
  1500. # (should follow the epsg line)
  1501. #
  1502. self.startpage.SetNext(self.csystemspage)
  1503. self.csystemspage.SetPrev(self.startpage)
  1504. self.csystemspage.SetNext(self.sumpage)
  1505. self.projpage.SetPrev(self.csystemspage)
  1506. self.projpage.SetNext(self.paramspage)
  1507. self.paramspage.SetPrev(self.projpage)
  1508. self.paramspage.SetNext(self.datumpage)
  1509. self.datumpage.SetPrev(self.paramspage)
  1510. self.datumpage.SetNext(self.sumpage)
  1511. self.ellipsepage.SetPrev(self.paramspage)
  1512. self.ellipsepage.SetNext(self.sumpage)
  1513. self.epsgpage.SetPrev(self.csystemspage)
  1514. self.epsgpage.SetNext(self.sumpage)
  1515. self.filepage.SetPrev(self.csystemspage)
  1516. self.filepage.SetNext(self.sumpage)
  1517. self.wktpage.SetPrev(self.csystemspage)
  1518. self.wktpage.SetNext(self.sumpage)
  1519. self.custompage.SetPrev(self.csystemspage)
  1520. self.custompage.SetNext(self.sumpage)
  1521. self.sumpage.SetPrev(self.csystemspage)
  1522. #
  1523. # do pages layout
  1524. #
  1525. self.startpage.DoLayout()
  1526. self.csystemspage.DoLayout()
  1527. self.projpage.DoLayout()
  1528. self.datumpage.DoLayout()
  1529. self.paramspage.DoLayout()
  1530. self.epsgpage.DoLayout()
  1531. self.filepage.DoLayout()
  1532. self.wktpage.DoLayout()
  1533. self.ellipsepage.DoLayout()
  1534. self.custompage.DoLayout()
  1535. self.sumpage.DoLayout()
  1536. self.wizard.FitToPage(self.datumpage)
  1537. size = self.wizard.GetPageSize()
  1538. self.wizard.SetPageSize((size[0], size[1] + 75))
  1539. # new location created?
  1540. self.location = None
  1541. success = False
  1542. # location created in different GIS database?
  1543. self.altdb = False
  1544. #
  1545. # run wizard...
  1546. #
  1547. if self.wizard.RunWizard(self.startpage):
  1548. msg = self.OnWizFinished()
  1549. if not msg:
  1550. self.wizard.Destroy()
  1551. self.location = self.startpage.location
  1552. if self.altdb == False:
  1553. dlg = wx.MessageDialog(parent = self.parent,
  1554. message = _("Do you want to set the default "
  1555. "region extents and resolution now?"),
  1556. caption = _("Location <%s> created") % self.location,
  1557. style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
  1558. dlg.CenterOnScreen()
  1559. if dlg.ShowModal() == wx.ID_YES:
  1560. dlg.Destroy()
  1561. defineRegion = RegionDef(self.parent, location = self.location)
  1562. defineRegion.CenterOnScreen()
  1563. defineRegion.Show()
  1564. else:
  1565. dlg.Destroy()
  1566. else: # -> error
  1567. self.wizard.Destroy()
  1568. GError(parent = self.parent,
  1569. message = "%s" % _("Unable to create new location. "
  1570. "Location <%(loc)s> not created.\n\n"
  1571. "Details: %(err)s") % \
  1572. { 'loc' : self.startpage.location,
  1573. 'err' : msg })
  1574. else: # -> canceled
  1575. self.wizard.Destroy()
  1576. GMessage(parent = self.parent,
  1577. message = _("Location wizard canceled. "
  1578. "Location not created."))
  1579. self.__cleanUp()
  1580. def __cleanUp(self):
  1581. global coordsys
  1582. global north
  1583. global south
  1584. global east
  1585. global west
  1586. global resolution
  1587. global wizerror
  1588. global translist
  1589. coordsys = None
  1590. north = None
  1591. south = None
  1592. east = None
  1593. west = None
  1594. resolution = None
  1595. transformlist = list()
  1596. def __readData(self):
  1597. """!Get georeferencing information from tables in $GISBASE/etc/proj"""
  1598. # read projection and parameters
  1599. f = open(os.path.join(globalvar.ETCDIR, "proj", "parms.table"), "r")
  1600. self.projections = {}
  1601. self.projdesc = {}
  1602. for line in f.readlines():
  1603. line = line.strip()
  1604. try:
  1605. proj, projdesc, params = line.split(':')
  1606. paramslist = params.split(';')
  1607. plist = []
  1608. for p in paramslist:
  1609. if p == '': continue
  1610. p1, pdefault = p.split(',')
  1611. pterm, pask = p1.split('=')
  1612. p = [pterm.strip(), pask.strip(), pdefault.strip()]
  1613. plist.append(p)
  1614. self.projections[proj.lower().strip()] = (projdesc.strip(), plist)
  1615. self.projdesc[proj.lower().strip()] = projdesc.strip()
  1616. except:
  1617. continue
  1618. f.close()
  1619. # read datum definitions
  1620. f = open(os.path.join(globalvar.ETCDIR, "proj", "datum.table"), "r")
  1621. self.datums = {}
  1622. paramslist = []
  1623. for line in f.readlines():
  1624. line = line.expandtabs(1)
  1625. line = line.strip()
  1626. if line == '' or line[0] == "#":
  1627. continue
  1628. datum, info = line.split(" ", 1)
  1629. info = info.strip()
  1630. datumdesc, params = info.split(" ", 1)
  1631. datumdesc = datumdesc.strip('"')
  1632. paramlist = params.split()
  1633. ellipsoid = paramlist.pop(0)
  1634. self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist)
  1635. f.close()
  1636. # read Earth-based ellipsiod definitions
  1637. f = open(os.path.join(globalvar.ETCDIR, "proj", "ellipse.table"), "r")
  1638. self.ellipsoids = {}
  1639. for line in f.readlines():
  1640. line = line.expandtabs(1)
  1641. line = line.strip()
  1642. if line == '' or line[0] == "#":
  1643. continue
  1644. ellipse, rest = line.split(" ", 1)
  1645. rest = rest.strip('" ')
  1646. desc, params = rest.split('"', 1)
  1647. desc = desc.strip('" ')
  1648. paramslist = params.split()
  1649. self.ellipsoids[ellipse] = (desc, paramslist)
  1650. f.close()
  1651. """
  1652. # read Planetary ellipsiod definitions
  1653. f = open(os.path.join(globalvar.ETCDIR, "proj", "ellipse.table.solar.system"), "r")
  1654. self.planetary_ellipsoids = {}
  1655. for line in f.readlines():
  1656. line = line.expandtabs(1)
  1657. line = line.strip()
  1658. if line == '' or line[0] == "#":
  1659. continue
  1660. ellipse, rest = line.split(" ", 1)
  1661. rest = rest.strip('" ')
  1662. desc, params = rest.split('"', 1)
  1663. desc = desc.strip('" ')
  1664. paramslist = params.split()
  1665. self.planetary_ellipsoids[ellipse] = (desc, paramslist)
  1666. f.close()
  1667. """
  1668. # read projection parameter description and parsing table
  1669. f = open(os.path.join(globalvar.ETCDIR, "proj", "desc.table"), "r")
  1670. self.paramdesc = {}
  1671. for line in f.readlines():
  1672. line = line.strip()
  1673. try:
  1674. pparam, datatype, proj4term, desc = line.split(':')
  1675. self.paramdesc[pparam] = (datatype, proj4term, desc)
  1676. except:
  1677. continue
  1678. f.close()
  1679. def OnWizFinished(self):
  1680. """!Wizard finished, create new location
  1681. @return error message on error
  1682. @return None on success
  1683. """
  1684. database = self.startpage.grassdatabase
  1685. location = self.startpage.location
  1686. # location already exists?
  1687. if os.path.isdir(os.path.join(database,location)):
  1688. GError(parent = self.wizard,
  1689. message = "%s <%s>: %s" % \
  1690. (_("Unable to create new location"),
  1691. os.path.join(database, location),
  1692. _("Location already exists in GRASS Database.")))
  1693. return None
  1694. # current GISDbase or a new one?
  1695. current_gdb = grass.gisenv()['GISDBASE']
  1696. if current_gdb != database:
  1697. # change to new GISDbase or create new one
  1698. if os.path.isdir(database) != True:
  1699. # create new directory
  1700. os.mkdir(database)
  1701. # change to new GISDbase directory
  1702. RunCommand('g.gisenv',
  1703. parent = self.wizard,
  1704. set = 'GISDBASE=%s' % database)
  1705. wx.MessageBox(parent = self.wizard,
  1706. message = _("Location <%(loc)s> will be created "
  1707. "in GIS data directory <%(dir)s>. "
  1708. "You will need to change the default GIS "
  1709. "data directory in the GRASS startup screen.") % \
  1710. { 'loc' : location, 'dir' : database},
  1711. caption = _("New GIS data directory"),
  1712. style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  1713. # location created in alternate GISDbase
  1714. self.altdb = True
  1715. global coordsys
  1716. try:
  1717. if coordsys == "xy":
  1718. grass.create_location(dbase = self.startpage.grassdatabase,
  1719. location = self.startpage.location,
  1720. desc = self.startpage.locTitle)
  1721. elif coordsys == "proj":
  1722. grass.create_location(dbase = self.startpage.grassdatabase,
  1723. location = self.startpage.location,
  1724. proj4 = self.CreateProj4String(),
  1725. datum = self.datumtrans,
  1726. desc = self.startpage.locTitle)
  1727. elif coordsys == 'custom':
  1728. grass.create_location(dbase = self.startpage.grassdatabase,
  1729. location = self.startpage.location,
  1730. proj4 = self.custompage.customstring,
  1731. desc = self.startpage.locTitle)
  1732. elif coordsys == "epsg":
  1733. if not self.epsgpage.epsgcode:
  1734. return _('EPSG code missing.')
  1735. grass.create_location(dbase = self.startpage.grassdatabase,
  1736. location = self.startpage.location,
  1737. epsg = self.epsgpage.epsgcode,
  1738. datum = self.datumtrans,
  1739. desc = self.startpage.locTitle)
  1740. elif coordsys == "file":
  1741. if not self.filepage.georeffile or \
  1742. not os.path.isfile(self.filepage.georeffile):
  1743. return _("File <%s> not found." % self.filepage.georeffile)
  1744. grass.create_location(dbase = self.startpage.grassdatabase,
  1745. location = self.startpage.location,
  1746. filename = self.filepage.georeffile,
  1747. desc = self.startpage.locTitle)
  1748. elif coordsys == "wkt":
  1749. if not self.wktpage.wktfile or \
  1750. not os.path.isfile(self.wktpage.wktfile):
  1751. return _("File <%s> not found." % self.wktpage.wktfile)
  1752. grass.create_location(dbase = self.startpage.grassdatabase,
  1753. location = self.startpage.location,
  1754. wkt = self.wktpage.wktfile,
  1755. desc = self.startpage.locTitle)
  1756. except grass.ScriptError, e:
  1757. return e.value
  1758. return None
  1759. def CreateProj4String(self):
  1760. """!Constract PROJ.4 string"""
  1761. location = self.startpage.location
  1762. proj = self.projpage.p4proj
  1763. projdesc = self.projpage.projdesc
  1764. proj4params = self.paramspage.p4projparams
  1765. datum = self.datumpage.datum
  1766. if self.datumpage.datumdesc:
  1767. datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse
  1768. else:
  1769. datumdesc = ''
  1770. datumparams = self.datumpage.datumparams
  1771. ellipse = self.ellipsepage.ellipse
  1772. ellipsedesc = self.ellipsepage.ellipsedesc
  1773. ellipseparams = self.ellipsepage.ellipseparams
  1774. #
  1775. # creating PROJ.4 string
  1776. #
  1777. proj4string = '%s %s' % (proj, proj4params)
  1778. # set ellipsoid parameters
  1779. if ellipse != '':
  1780. proj4string = '%s +ellps=%s' % (proj4string, ellipse)
  1781. for item in ellipseparams:
  1782. if item[:4] == 'f=1/':
  1783. item = ' +rf=' + item[4:]
  1784. else:
  1785. item = ' +' + item
  1786. proj4string = '%s %s' % (proj4string, item)
  1787. # set datum and transform parameters if relevant
  1788. if datum != '':
  1789. proj4string = '%s +datum=%s' % (proj4string, datum)
  1790. if datumparams:
  1791. for item in datumparams:
  1792. proj4string = '%s +%s' % (proj4string,item)
  1793. proj4string = '%s +no_defs' % proj4string
  1794. return proj4string