wizard.py 94 KB

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