wizard.py 96 KB

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