wizard.py 79 KB

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