location_wizard.py 104 KB

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