wizard.py 97 KB

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