location_wizard.py 103 KB

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