location_wizard.py 103 KB

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