wizard.py 95 KB

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