location_wizard.py 104 KB

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