location_wizard.py 103 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784
  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. self.pval[event.GetId() - 2000] = event.GetString()
  613. def OnPageChange(self,event=None):
  614. if event.GetDirection():
  615. self.p4projparams = ''
  616. for num in range(self.pcount + 1):
  617. if self.ptype[num] == 'bool':
  618. if self.pval[num] == 'N':
  619. continue
  620. else:
  621. self.p4projparams += (' +' + self.proj4param[num])
  622. else:
  623. if self.pval[num] == '':
  624. wx.MessageBox('You must enter a value for %s' % self.pdesc[num],
  625. 'Something is missing!', wx.ICON_ERROR)
  626. event.Veto()
  627. else:
  628. self.p4projparams += (' +' + self.proj4param[num] + '=' + self.pval[num])
  629. def OnEnterPage(self,event):
  630. self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
  631. try:
  632. # page already formatted
  633. if self.pagesizer.GetItem(self.panel) != '':
  634. pass
  635. except:
  636. # entering page for the first time
  637. paramSBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
  638. label=_(" Enter parameters for %s projection ") % self.projdesc)
  639. paramSBSizer = wx.StaticBoxSizer(paramSBox)
  640. self.panel = scrolled.ScrolledPanel(self, wx.ID_ANY)
  641. self.prjparamsizer = wx.GridBagSizer(vgap=0, hgap=0)
  642. self.panel.SetupScrolling()
  643. # this ought to work but it doesn't
  644. # self.sizer.Add(paramSBSizer, pos=(2,1), span=(3,2),
  645. # flag=wx.EXPAND )
  646. self.pagesizer.Add(paramSBSizer, proportion=1,
  647. flag=wx.EXPAND | wx.ALIGN_TOP | wx.ALL, border=10)
  648. paramSBSizer.Add(self.panel, proportion=1,
  649. flag=wx.ALIGN_CENTER|wx.EXPAND)
  650. paramSBSizer.Fit(self.panel)
  651. self.panel.SetSizer(self.prjparamsizer)
  652. if event.GetDirection():
  653. self.pcount = 0
  654. self.prjparamsizer.Clear(True)
  655. num = 0
  656. for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
  657. # get parameters
  658. self.pcount = num
  659. self.ptype[num] = self.parent.paramdesc[paramgrp[0]][0]
  660. self.proj4param[num] = self.parent.paramdesc[paramgrp[0]][1]
  661. self.pdesc[num] = self.parent.paramdesc[paramgrp[0]][2]
  662. # default values
  663. if self.ptype[num] == 'bool': self.pval[num] = 'N'
  664. elif self.ptype[num] == 'zone': self.pval[num] = '30'
  665. else: self.pval[num] = paramgrp[2]
  666. label = wx.StaticText(self.panel, id=1000+num, label=self.pdesc[num],
  667. style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
  668. if self.ptype[num] == 'bool':
  669. self.pentry[num] = wx.Choice(self.panel, id=2000+num, size=(100,-1),
  670. choices = ['N','Y'])
  671. self.pentry[num].SetStringSelection(self.pval[num])
  672. self.Bind(wx.EVT_CHOICE, self.OnParamEntry)
  673. elif self.ptype[num] == 'zone':
  674. zone = []
  675. for i in range(1, 61):
  676. zone.append(str(i))
  677. self.pentry[num] = wx.Choice(self.panel, id=2000+num, size=(100,-1),
  678. choices = zone)
  679. self.pentry[num].SetStringSelection(self.pval[num])
  680. self.Bind(wx.EVT_CHOICE, self.OnParamEntry)
  681. else:
  682. self.pentry[num] = wx.TextCtrl(self.panel, id=2000+num, value=self.pval[num],
  683. size=(100,-1))
  684. self.Bind(wx.EVT_TEXT, self.OnParamEntry)
  685. if paramgrp[1] == 'noask':
  686. self.pentry[num].SetEditable(False)
  687. self.pentry[num].SetBackgroundColour(wx.LIGHT_GREY)
  688. self.prjparamsizer.Add(item=label, pos=(num, 1),
  689. flag=wx.ALIGN_RIGHT | wx.RIGHT, border=5)
  690. self.prjparamsizer.Add(item=self.pentry[num], pos=(num, 2),
  691. flag=wx.ALIGN_LEFT | wx.LEFT, border=5)
  692. num += 1
  693. self.panel.SetSize(self.panel.GetBestSize())
  694. self.panel.Layout()
  695. self.Layout()
  696. self.Update()
  697. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  698. wx.FindWindowById(wx.ID_FORWARD).Enable()
  699. event.Skip()
  700. def SetVal(self, event):
  701. if event.GetId() == self.radio1.GetId():
  702. self.SetNext(self.parent.datumpage)
  703. self.parent.sumpage.SetPrev(self.parent.datumpage)
  704. elif event.GetId() == self.radio2.GetId():
  705. self.SetNext(self.parent.ellipsepage)
  706. self.parent.sumpage.SetPrev(self.parent.ellipsepage)
  707. def GetUTM(self, event):
  708. self.utmzone = event.GetString()
  709. def OnHemisphere(self, event):
  710. self.utmhemisphere = event.GetString()
  711. class DatumPage(TitledPage):
  712. """
  713. Wizard page for selecting datum (with associated ellipsoid)
  714. and datum transformation parameters (select coordinate system option)
  715. """
  716. def __init__(self, wizard, parent):
  717. TitledPage.__init__(self, wizard, _("Specify geodetic datum"))
  718. self.parent = parent
  719. self.datum = ''
  720. self.datumdesc = ''
  721. self.ellipse = ''
  722. self.datumparams = ''
  723. self.proj4params = ''
  724. # text input
  725. self.tdatum = self.MakeTextCtrl("", size=(200,-1))
  726. # search box
  727. self.searchb = wx.SearchCtrl(self, size=(200,-1),
  728. style=wx.TE_PROCESS_ENTER)
  729. # create list control for datum/elipsoid list
  730. data = []
  731. for key in self.parent.datums.keys():
  732. data.append([key, self.parent.datums[key][0], self.parent.datums[key][1]])
  733. self.datumlist = ItemList(self,
  734. data=data,
  735. columns=[_('Code'), _('Ellipsoid'), _('Description')])
  736. self.datumlist.resizeLastColumn(10)
  737. # layout
  738. self.sizer.AddGrowableCol(4)
  739. self.sizer.Add(item=self.MakeLabel(_("Datum code:")),
  740. flag=wx.ALIGN_LEFT |
  741. wx.ALIGN_CENTER_VERTICAL |
  742. wx.ALL, border=5, pos=(1, 1))
  743. self.sizer.Add(item=self.tdatum,
  744. flag=wx.ALIGN_LEFT |
  745. wx.ALIGN_CENTER_VERTICAL |
  746. wx.ALL, border=5, pos=(1, 2))
  747. self.sizer.Add(item=self.MakeLabel(_("Search in description:")),
  748. flag=wx.ALIGN_LEFT |
  749. wx.ALIGN_CENTER_VERTICAL |
  750. wx.ALL, border=5, pos=(2, 1))
  751. self.sizer.Add(item=self.searchb,
  752. flag=wx.ALIGN_LEFT |
  753. wx.ALIGN_CENTER_VERTICAL |
  754. wx.ALL, border=5, pos=(2, 2))
  755. self.sizer.AddGrowableRow(3)
  756. self.sizer.Add(item=self.datumlist,
  757. flag=wx.EXPAND |
  758. wx.ALIGN_LEFT |
  759. wx.ALL, border=5, pos=(3, 1), span=(1, 4))
  760. # events
  761. self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected)
  762. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDSearch)
  763. self.tdatum.Bind(wx.EVT_TEXT, self.OnDText)
  764. self.tdatum.Bind(wx.EVT_TEXT_ENTER, self.OnDText)
  765. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  766. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  767. # do page layout
  768. # self.DoLayout()
  769. def OnPageChanging(self, event):
  770. self.proj4params = ''
  771. proj = self.parent.projpage.p4proj
  772. if event.GetDirection():
  773. if self.datum not in self.parent.datums:
  774. event.Veto()
  775. else:
  776. # check for datum tranforms
  777. # proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
  778. ret = gcmd.RunCommand('g.proj',
  779. read = True,
  780. proj4 = '%s +datum=%s' % (proj, self.datum),
  781. datumtrans = '-1')
  782. if ret != '':
  783. dtrans = ''
  784. # open a dialog to select datum transform number
  785. dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
  786. if dlg.ShowModal() == wx.ID_OK:
  787. dtrans = dlg.GetTransform()
  788. if dtrans == '':
  789. dlg.Destroy()
  790. event.Veto()
  791. return 'Datum transform is required.'
  792. else:
  793. dlg.Destroy()
  794. event.Veto()
  795. return 'Datum transform is required.'
  796. self.parent.datumtrans = dtrans
  797. self.GetNext().SetPrev(self)
  798. self.parent.ellipsepage.ellipse = self.ellipse
  799. self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  800. def OnEnterPage(self,event):
  801. self.parent.datumtrans = 0
  802. if event.GetDirection():
  803. if len(self.datum) == 0:
  804. # disable 'next' button by default when entering from previous page
  805. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  806. else:
  807. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  808. event.Skip()
  809. def OnDText(self, event):
  810. self.datum = event.GetString()
  811. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  812. if len(self.datum) == 0 or self.datum not in self.parent.datums:
  813. nextButton.Enable(False)
  814. else:
  815. self.ellipse = self.parent.datums[self.datum][0]
  816. self.datumdesc = self.parent.datums[self.datum][1]
  817. self.datumparams = self.parent.datums[self.datum][2]
  818. try:
  819. self.datumparams.remove('dx=0.0')
  820. except:
  821. pass
  822. try:
  823. self.datumparams.remove('dy=0.0')
  824. except:
  825. pass
  826. try:
  827. self.datumparams.remove('dz=0.0')
  828. except:
  829. pass
  830. nextButton.Enable(True)
  831. self.Update()
  832. event.Skip()
  833. def OnDSearch(self, event):
  834. str = self.searchb.GetValue()
  835. try:
  836. self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search(index=[0,1,2], pattern=str)
  837. except:
  838. self.datum = self.datumdesc = self.ellipsoid = ''
  839. event.Skip()
  840. def OnDatumSelected(self, event):
  841. index = event.m_itemIndex
  842. item = event.GetItem()
  843. self.datum = self.datumlist.GetItem(index, 0).GetText()
  844. self.tdatum.SetValue(self.datum)
  845. event.Skip()
  846. class EllipsePage(TitledPage):
  847. """
  848. Wizard page for selecting ellipsoid (select coordinate system option)
  849. """
  850. def __init__(self, wizard, parent):
  851. TitledPage.__init__(self, wizard, _("Specify ellipsoid"))
  852. self.parent = parent
  853. self.ellipse = ''
  854. self.ellipsedesc = ''
  855. self.ellipseparams = ''
  856. self.proj4params = ''
  857. # text input
  858. self.tellipse = self.MakeTextCtrl("", size=(200,-1))
  859. # search box
  860. self.searchb = wx.SearchCtrl(self, size=(200,-1),
  861. style=wx.TE_PROCESS_ENTER)
  862. # create list control for ellipse list
  863. data = []
  864. # extract code, desc
  865. for key in self.parent.ellipsoids.keys():
  866. data.append([key, self.parent.ellipsoids[key][0]])
  867. self.ellipselist = ItemList(self, data=data,
  868. columns=[_('Code'), _('Description')])
  869. self.ellipselist.resizeLastColumn(30)
  870. # layout
  871. self.sizer.AddGrowableCol(4)
  872. self.sizer.Add(item=self.MakeLabel(_("Ellipsoid code:")),
  873. flag=wx.ALIGN_RIGHT |
  874. wx.ALIGN_CENTER_VERTICAL |
  875. wx.ALL, border=5, pos=(1, 1))
  876. self.sizer.Add(item=self.tellipse,
  877. flag=wx.ALIGN_LEFT |
  878. wx.ALIGN_CENTER_VERTICAL |
  879. wx.ALL, border=5, pos=(1, 2))
  880. self.sizer.Add(item=self.MakeLabel(_("Search in description:")),
  881. flag=wx.ALIGN_RIGHT |
  882. wx.ALIGN_CENTER_VERTICAL |
  883. wx.ALL, border=5, pos=(2, 1))
  884. self.sizer.Add(item=self.searchb,
  885. flag=wx.ALIGN_LEFT |
  886. wx.ALIGN_CENTER_VERTICAL |
  887. wx.ALL, border=5, pos=(2, 2))
  888. self.sizer.AddGrowableRow(3)
  889. self.sizer.Add(item=self.ellipselist,
  890. flag=wx.EXPAND |
  891. wx.ALIGN_LEFT |
  892. wx.ALL, border=5, pos=(3, 1), span=(1, 4))
  893. # events
  894. self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  895. self.tellipse.Bind(wx.EVT_TEXT, self.OnText)
  896. self.tellipse.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  897. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  898. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  899. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  900. def OnEnterPage(self,event):
  901. if len(self.ellipse) == 0:
  902. # disable 'next' button by default
  903. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  904. else:
  905. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  906. event.Skip()
  907. def OnPageChanging(self, event):
  908. if event.GetDirection() and self.ellipse not in self.parent.ellipsoids:
  909. event.Veto()
  910. self.proj4params = ''
  911. self.GetNext().SetPrev(self)
  912. self.parent.datumpage.datumparams = ''
  913. # self.GetNext().SetPrev(self) (???)
  914. def OnText(self, event):
  915. """!Ellipspoid code changed"""
  916. self.ellipse = event.GetString()
  917. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  918. if len(self.ellipse) == 0 or self.ellipse not in self.parent.ellipsoids:
  919. nextButton.Enable(False)
  920. self.ellipsedesc = ''
  921. self.ellipseparams = ''
  922. self.proj4params = ''
  923. elif self.ellipse in self.parent.ellipsoids:
  924. self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0]
  925. self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  926. nextButton.Enable(True)
  927. def OnSearch(self, event):
  928. """!Search ellipsoid by desc"""
  929. try:
  930. self.ellipse, self.ellipsedesc = \
  931. self.ellipselist.Search(index=[0,1], pattern=event.GetString())
  932. self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  933. except:
  934. self.ellipse = self.ellipsedesc = self.ellipseparams = ''
  935. event.Skip()
  936. def OnItemSelected(self,event):
  937. index = event.m_itemIndex
  938. item = event.GetItem()
  939. self.ellipse = self.ellipselist.GetItem(index, 0).GetText()
  940. self.tellipse.SetValue(self.ellipse)
  941. event.Skip()
  942. class GeoreferencedFilePage(TitledPage):
  943. """
  944. Wizard page for selecting georeferenced file to use
  945. for setting coordinate system parameters
  946. """
  947. def __init__(self, wizard, parent):
  948. TitledPage.__init__(self, wizard, _("Select georeferenced file"))
  949. self.georeffile = ''
  950. # create controls
  951. self.lfile= self.MakeLabel(_("Georeferenced file:"))
  952. self.tfile = self.MakeTextCtrl(size=(300,-1))
  953. self.bbrowse = self.MakeButton(_("Browse"))
  954. # do layout
  955. self.sizer.AddGrowableCol(3)
  956. self.sizer.Add(item=self.lfile, flag=wx.ALIGN_LEFT |
  957. wx.ALIGN_CENTRE_VERTICAL |
  958. wx.ALL, border=5, pos=(1, 1))
  959. self.sizer.Add(item=self.tfile, flag=wx.ALIGN_LEFT |
  960. wx.ALIGN_CENTRE_VERTICAL |
  961. wx.ALL, border=5, pos=(1, 2))
  962. self.sizer.Add(item=self.bbrowse, flag=wx.ALIGN_LEFT |
  963. wx.ALL, border=5, pos=(1, 3))
  964. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  965. self.tfile.Bind(wx.EVT_TEXT, self.OnText)
  966. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  967. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  968. # do page layout
  969. # self.DoLayout()
  970. def OnEnterPage(self, event):
  971. if len(self.georeffile) == 0:
  972. # disable 'next' button by default
  973. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  974. else:
  975. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  976. event.Skip()
  977. def OnPageChanging(self, event):
  978. if event.GetDirection() and self.georeffile == '':
  979. event.Veto()
  980. self.GetNext().SetPrev(self)
  981. event.Skip()
  982. def OnText(self, event):
  983. self.georeffile = event.GetString()
  984. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  985. if len(self.georeffile) > 0 and os.path.isfile(self.georeffile):
  986. if not nextButton.IsEnabled():
  987. nextButton.Enable(True)
  988. else:
  989. if nextButton.IsEnabled():
  990. nextButton.Enable(False)
  991. event.Skip()
  992. def OnBrowse(self, event):
  993. """!Choose file"""
  994. dlg = wx.FileDialog(self,
  995. _("Select georeferenced file"),
  996. os.getcwd(), "", "*.*", wx.OPEN)
  997. if dlg.ShowModal() == wx.ID_OK:
  998. path = dlg.GetPath()
  999. self.tfile.SetValue(path)
  1000. dlg.Destroy()
  1001. event.Skip()
  1002. def OnCreate(self, event):
  1003. pass
  1004. class WKTPage(TitledPage):
  1005. """
  1006. Wizard page for selecting WKT file to use
  1007. for setting coordinate system parameters
  1008. """
  1009. def __init__(self, wizard, parent):
  1010. TitledPage.__init__(self, wizard, _("Select WKT file"))
  1011. self.wktfile = ''
  1012. # create controls
  1013. self.lfile= self.MakeLabel(_("WKT file:"))
  1014. self.tfile = self.MakeTextCtrl(size=(300,-1))
  1015. self.bbrowse = self.MakeButton(_("Browse"))
  1016. # do layout
  1017. self.sizer.AddGrowableCol(3)
  1018. self.sizer.Add(item=self.lfile, flag=wx.ALIGN_LEFT |
  1019. wx.ALIGN_CENTRE_VERTICAL |
  1020. wx.ALL, border=5, pos=(1, 1))
  1021. self.sizer.Add(item=self.tfile, flag=wx.ALIGN_LEFT |
  1022. wx.ALIGN_CENTRE_VERTICAL |
  1023. wx.ALL, border=5, pos=(1, 2))
  1024. self.sizer.Add(item=self.bbrowse, flag=wx.ALIGN_LEFT |
  1025. wx.ALL, border=5, pos=(1, 3))
  1026. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  1027. self.tfile.Bind(wx.EVT_TEXT, self.OnText)
  1028. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1029. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1030. def OnEnterPage(self, event):
  1031. if len(self.wktfile) == 0:
  1032. # disable 'next' button by default
  1033. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1034. else:
  1035. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1036. event.Skip()
  1037. def OnPageChanging(self, event):
  1038. if event.GetDirection() and self.wktfile == '':
  1039. event.Veto()
  1040. self.GetNext().SetPrev(self)
  1041. event.Skip()
  1042. def OnText(self, event):
  1043. self.wktfile = event.GetString()
  1044. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1045. if len(self.wktfile) > 0 and os.path.isfile(self.wktfile):
  1046. if not nextButton.IsEnabled():
  1047. nextButton.Enable(True)
  1048. else:
  1049. if nextButton.IsEnabled():
  1050. nextButton.Enable(False)
  1051. event.Skip()
  1052. def OnBrowse(self, event):
  1053. """!Choose file"""
  1054. dlg = wx.FileDialog(self,
  1055. _("Select WKT file"),
  1056. os.getcwd(), "", "*.*", wx.OPEN)
  1057. if dlg.ShowModal() == wx.ID_OK:
  1058. path = dlg.GetPath()
  1059. self.tfile.SetValue(path)
  1060. dlg.Destroy()
  1061. event.Skip()
  1062. def OnCreate(self, event):
  1063. pass
  1064. class EPSGPage(TitledPage):
  1065. """
  1066. Wizard page for selecting EPSG code for
  1067. setting coordinate system parameters
  1068. """
  1069. def __init__(self, wizard, parent):
  1070. TitledPage.__init__(self, wizard, _("Choose EPSG Code"))
  1071. self.parent = parent
  1072. self.epsgCodeDict = {}
  1073. self.epsgcode = None
  1074. self.epsgdesc = ''
  1075. self.epsgparams = ''
  1076. # labels
  1077. self.lfile= self.MakeLabel(_("Path to the EPSG-codes file:"),
  1078. style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  1079. self.lcode= self.MakeLabel(_("EPSG code:"),
  1080. style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  1081. # text input
  1082. epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
  1083. self.tfile = self.MakeTextCtrl(text=epsgdir, size=(200,-1))
  1084. self.tcode = self.MakeTextCtrl(size=(200,-1))
  1085. # buttons
  1086. self.bbrowse = self.MakeButton(_("Browse"))
  1087. # self.bbcodes = self.MakeButton(_("Reload EPSG Codes"))
  1088. # search box
  1089. self.searchb = wx.SearchCtrl(self, size=(200,-1),
  1090. style=wx.TE_PROCESS_ENTER)
  1091. self.epsglist = ItemList(self, data=None,
  1092. columns=[_('Code'), _('Description'), _('Parameters')])
  1093. # layout
  1094. self.sizer.AddGrowableCol(3)
  1095. self.sizer.Add(item=self.lfile,
  1096. flag=wx.ALIGN_LEFT |
  1097. wx.ALIGN_CENTER_VERTICAL |
  1098. wx.ALL, border=5, pos=(1, 1), span=(1, 2))
  1099. self.sizer.Add(item=self.tfile,
  1100. flag=wx.ALIGN_LEFT |
  1101. wx.ALIGN_CENTER_VERTICAL |
  1102. wx.ALL, border=5, pos=(1, 3))
  1103. self.sizer.Add(item=self.bbrowse,
  1104. flag=wx.ALIGN_LEFT |
  1105. wx.ALIGN_CENTER_VERTICAL |
  1106. wx.ALL, border=5, pos=(1, 4))
  1107. self.sizer.Add(item=self.lcode,
  1108. flag=wx.ALIGN_LEFT |
  1109. wx.ALIGN_CENTER_VERTICAL |
  1110. wx.ALL, border=5, pos=(2, 1), span=(1, 2))
  1111. self.sizer.Add(item=self.tcode,
  1112. flag=wx.ALIGN_LEFT |
  1113. wx.ALIGN_CENTER_VERTICAL |
  1114. wx.ALL, border=5, pos=(2, 3))
  1115. self.sizer.Add(item=self.searchb,
  1116. flag=wx.ALIGN_LEFT |
  1117. wx.ALIGN_CENTER_VERTICAL |
  1118. wx.ALL, border=5, pos=(3, 3))
  1119. # self.sizer.Add(item=self.bbcodes,
  1120. # flag=wx.ALIGN_LEFT |
  1121. # wx.ALIGN_CENTER_VERTICAL |
  1122. # wx.ALL, border=5, pos=(3, 4))
  1123. self.sizer.AddGrowableRow(4)
  1124. self.sizer.Add(item=self.epsglist,
  1125. flag=wx.ALIGN_LEFT | wx.EXPAND, pos=(4, 1),
  1126. span=(1, 4))
  1127. # events
  1128. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  1129. # self.bbcodes.Bind(wx.EVT_BUTTON, self.OnBrowseCodes)
  1130. self.tcode.Bind(wx.EVT_TEXT, self.OnText)
  1131. self.tcode.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  1132. self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  1133. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  1134. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1135. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1136. def OnEnterPage(self, event):
  1137. self.parent.datumtrans = 0
  1138. if event.GetDirection():
  1139. if not self.epsgcode:
  1140. # disable 'next' button by default
  1141. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1142. else:
  1143. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1144. # load default epsg database file
  1145. self.OnBrowseCodes(None)
  1146. event.Skip()
  1147. def OnPageChanging(self, event):
  1148. if event.GetDirection():
  1149. if not self.epsgcode:
  1150. event.Veto()
  1151. return
  1152. else:
  1153. # check for datum transforms
  1154. ret = gcmd.RunCommand('g.proj',
  1155. read = True,
  1156. epsg = self.epsgcode,
  1157. datumtrans = '-1')
  1158. if ret != '':
  1159. dtrans = ''
  1160. # open a dialog to select datum transform number
  1161. dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
  1162. if dlg.ShowModal() == wx.ID_OK:
  1163. dtrans = dlg.GetTransform()
  1164. if dtrans == '':
  1165. dlg.Destroy()
  1166. event.Veto()
  1167. return 'Datum transform is required.'
  1168. else:
  1169. dlg.Destroy()
  1170. event.Veto()
  1171. return 'Datum transform is required.'
  1172. self.parent.datumtrans = dtrans
  1173. self.GetNext().SetPrev(self)
  1174. def OnText(self, event):
  1175. self.epsgcode = event.GetString()
  1176. try:
  1177. self.epsgcode = int(self.epsgcode)
  1178. except:
  1179. self.epsgcode = None
  1180. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1181. if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys():
  1182. self.epsgdesc = self.epsgCodeDict[self.epsgcode][0]
  1183. self.epsgparams = self.epsgCodeDict[self.epsgcode][1]
  1184. if not nextButton.IsEnabled():
  1185. nextButton.Enable(True)
  1186. else:
  1187. self.epsgcode = None # not found
  1188. if nextButton.IsEnabled():
  1189. nextButton.Enable(False)
  1190. self.epsgdesc = self.epsgparams = ''
  1191. def OnSearch(self, event):
  1192. value = self.searchb.GetValue()
  1193. if value == '':
  1194. self.epsgcode = None
  1195. self.epsgdesc = self.epsgparams = ''
  1196. self.tcode.SetValue('')
  1197. self.searchb.SetValue('')
  1198. self.OnBrowseCodes(None)
  1199. else:
  1200. try:
  1201. self.epsgcode, self.epsgdesc, self.epsgparams = \
  1202. self.epsglist.Search(index=[0,1,2], pattern=value)
  1203. except IndexError: # -> no item found
  1204. self.epsgcode = None
  1205. self.epsgdesc = self.epsgparams = ''
  1206. self.tcode.SetValue('')
  1207. self.searchb.SetValue('')
  1208. event.Skip()
  1209. def OnBrowse(self, event):
  1210. """!Define path for EPSG code file"""
  1211. path = os.path.dirname(self.tfile.GetValue())
  1212. if not path:
  1213. path = os.getcwd()
  1214. dlg = wx.FileDialog(parent=self, message=_("Choose EPSG codes file"),
  1215. defaultDir=path, defaultFile="", wildcard="*", style=wx.OPEN)
  1216. if dlg.ShowModal() == wx.ID_OK:
  1217. path = dlg.GetPath()
  1218. self.tfile.SetValue(path)
  1219. self.OnBrowseCodes(None)
  1220. dlg.Destroy()
  1221. event.Skip()
  1222. def OnItemSelected(self, event):
  1223. """!EPSG code selected from the list"""
  1224. index = event.m_itemIndex
  1225. item = event.GetItem()
  1226. self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText())
  1227. self.epsgdesc = self.epsglist.GetItem(index, 1).GetText()
  1228. self.tcode.SetValue(str(self.epsgcode))
  1229. event.Skip()
  1230. def OnBrowseCodes(self, event, search=None):
  1231. """!Browse EPSG codes"""
  1232. self.epsgCodeDict = utils.ReadEpsgCodes(self.tfile.GetValue())
  1233. if type(self.epsgCodeDict) == type(''):
  1234. wx.MessageBox(parent=self,
  1235. message=_("Unable to read EPGS codes: %s") % self.epsgCodeDict,
  1236. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1237. self.epsglist.Populate([], update=True)
  1238. return
  1239. data = []
  1240. for code, val in self.epsgCodeDict.iteritems():
  1241. if code is not None:
  1242. data.append((code, val[0], val[1]))
  1243. self.epsglist.Populate(data, update=True)
  1244. class CustomPage(TitledPage):
  1245. """
  1246. Wizard page for entering custom PROJ.4 string
  1247. for setting coordinate system parameters
  1248. """
  1249. def __init__(self, wizard, parent):
  1250. TitledPage.__init__(self, wizard,
  1251. _("Choose method of specifying georeferencing parameters"))
  1252. global coordsys
  1253. self.customstring = ''
  1254. self.parent = parent
  1255. # widgets
  1256. self.text_proj4string = self.MakeTextCtrl(size=(400, 200),
  1257. style=wx.TE_MULTILINE)
  1258. self.label_proj4string = self.MakeLabel(_("Enter PROJ.4 parameters string:"))
  1259. # layout
  1260. self.sizer.AddGrowableCol(2)
  1261. self.sizer.Add(self.label_proj4string,
  1262. flag=wx.ALIGN_LEFT | wx.ALL,
  1263. border=5, pos=(1, 1))
  1264. self.sizer.AddGrowableRow(2)
  1265. self.sizer.Add(self.text_proj4string,
  1266. flag=wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
  1267. border=5, pos=(2, 1), span=(1, 2))
  1268. self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring)
  1269. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1270. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1271. def OnEnterPage(self, event):
  1272. if len(self.customstring) == 0:
  1273. # disable 'next' button by default
  1274. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1275. else:
  1276. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1277. event.Skip()
  1278. def OnPageChanging(self, event):
  1279. if event.GetDirection() and not self.customstring:
  1280. event.Veto()
  1281. else:
  1282. # check for datum tranforms
  1283. ret, out, err = gcmd.RunCommand('g.proj',
  1284. read = True, getErrorMsg = True,
  1285. proj4 = self.customstring,
  1286. datumtrans = '-1')
  1287. if ret != 0:
  1288. wx.MessageBox(err, 'g.proj error: check PROJ4 parameter string')
  1289. event.Veto()
  1290. return
  1291. if out != '':
  1292. dtrans = ''
  1293. # open a dialog to select datum transform number
  1294. dlg = SelectTransformDialog(self.parent.parent, transforms=out)
  1295. if dlg.ShowModal() == wx.ID_OK:
  1296. dtrans = dlg.GetTransform()
  1297. if dtrans == '':
  1298. dlg.Destroy()
  1299. event.Veto()
  1300. return 'Datum transform is required.'
  1301. else:
  1302. dlg.Destroy()
  1303. event.Veto()
  1304. return 'Datum transform is required.'
  1305. self.parent.datumtrans = dtrans
  1306. self.GetNext().SetPrev(self)
  1307. def GetProjstring(self, event):
  1308. """!Change proj string"""
  1309. # TODO: check PROJ.4 syntax
  1310. self.customstring = event.GetString()
  1311. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1312. if len(self.customstring) == 0:
  1313. if nextButton.IsEnabled():
  1314. nextButton.Enable(False)
  1315. else:
  1316. if not nextButton.IsEnabled():
  1317. nextButton.Enable()
  1318. class SummaryPage(TitledPage):
  1319. """
  1320. Shows summary result of choosing coordinate system parameters
  1321. prior to creating location
  1322. """
  1323. def __init__(self, wizard, parent):
  1324. TitledPage.__init__(self, wizard, _("Summary"))
  1325. self.parent = parent
  1326. # labels
  1327. self.ldatabase = self.MakeLabel("")
  1328. self.llocation = self.MakeLabel("")
  1329. self.lprojection = self.MakeLabel("")
  1330. self.lproj4string = self.MakeLabel("")
  1331. self.lproj4stringLabel = self.MakeLabel("")
  1332. self.lprojection.Wrap(400)
  1333. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1334. # self.Bind(wx.EVT_BUTTON, self.OnFinish, wx.ID_FINISH)
  1335. # do sub-page layout
  1336. self.__DoLayout()
  1337. def __DoLayout(self):
  1338. """!Do page layout"""
  1339. self.sizer.AddGrowableCol(1)
  1340. self.sizer.Add(item=self.MakeLabel(_("GRASS Database:")),
  1341. flag=wx.ALIGN_LEFT | wx.ALL,
  1342. border=5, pos=(1, 0))
  1343. self.sizer.Add(item=self.ldatabase,
  1344. flag=wx.ALIGN_LEFT | wx.ALL,
  1345. border=5, pos=(1, 1))
  1346. self.sizer.Add(item=self.MakeLabel(_("Location Name:")),
  1347. flag=wx.ALIGN_LEFT | wx.ALL,
  1348. border=5, pos=(2, 0))
  1349. self.sizer.Add(item=self.llocation,
  1350. flag=wx.ALIGN_LEFT | wx.ALL,
  1351. border=5, pos=(2, 1))
  1352. self.sizer.Add(item=self.MakeLabel(_("Projection:")),
  1353. flag=wx.ALIGN_LEFT | wx.ALL,
  1354. border=5, pos=(3, 0))
  1355. self.sizer.Add(item=self.lprojection,
  1356. flag=wx.ALIGN_LEFT | wx.ALL,
  1357. border=5, pos=(3, 1))
  1358. self.sizer.Add(item=self.lproj4stringLabel,
  1359. flag=wx.ALIGN_LEFT | wx.ALL,
  1360. border=5, pos=(4, 0))
  1361. self.sizer.Add(item=self.lproj4string,
  1362. flag=wx.ALIGN_LEFT | wx.ALL,
  1363. border=5, pos=(4, 1))
  1364. self.sizer.Add(item=(10,20),
  1365. flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
  1366. border=5, pos=(5, 0), span=(1, 2))
  1367. def OnEnterPage(self,event):
  1368. """
  1369. Insert values into text controls for summary of location creation options
  1370. """
  1371. database = self.parent.startpage.grassdatabase
  1372. location = self.parent.startpage.location
  1373. proj4string = self.parent.CreateProj4String()
  1374. epsgcode = self.parent.epsgpage.epsgcode
  1375. dtrans = self.parent.datumtrans
  1376. global coordsys
  1377. if coordsys not in ['proj', 'epsg']:
  1378. self.lproj4stringLabel.Hide()
  1379. self.lproj4string.Hide()
  1380. self.lproj4stringLabel.SetLabel('')
  1381. self.lproj4string.SetLabel('')
  1382. else:
  1383. self.lproj4string.Show()
  1384. self.lproj4stringLabel.SetLabel(_("PROJ.4 definition:"))
  1385. if coordsys == 'proj':
  1386. ret, msg, err = gcmd.RunCommand('g.proj',
  1387. flags = 'j',
  1388. proj4 = proj4string,
  1389. datumtrans = dtrans,
  1390. location = location,
  1391. getErrorMsg = True,
  1392. read = True)
  1393. elif coordsys == 'epsg':
  1394. ret, msg, err = gcmd.RunCommand('g.proj',
  1395. flags = 'j',
  1396. epsg = epsgcode,
  1397. datumtrans = dtrans,
  1398. location = location,
  1399. getErrorMsg = True,
  1400. read = True)
  1401. if ret == 0:
  1402. projlabel = ''
  1403. for line in msg.splitlines():
  1404. projlabel = projlabel + '%s ' % line
  1405. self.lproj4string.SetLabel(projlabel)
  1406. else:
  1407. wx.MessageBox(err, 'Error', wx.ICON_ERROR)
  1408. self.lproj4string.Wrap(400)
  1409. projdesc = self.parent.projpage.projdesc
  1410. ellipsedesc = self.parent.ellipsepage.ellipsedesc
  1411. datumdesc = self.parent.datumpage.datumdesc
  1412. self.ldatabase.SetLabel(str(database))
  1413. self.llocation.SetLabel(str(location))
  1414. label = ''
  1415. if coordsys == 'epsg':
  1416. label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
  1417. self.lprojection.SetLabel(label)
  1418. elif coordsys == 'file':
  1419. label = 'matches file %s' % self.parent.filepage.georeffile
  1420. self.lprojection.SetLabel(label)
  1421. elif coordsys == 'wkt':
  1422. label = 'matches file %s' % self.parent.wktpage.wktfile
  1423. self.lprojection.SetLabel(label)
  1424. elif coordsys == 'proj':
  1425. label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
  1426. self.lprojection.SetLabel(label)
  1427. elif coordsys == 'xy':
  1428. label = ('XY coordinate system (not projected).')
  1429. self.lprojection.SetLabel(label)
  1430. elif coordsys == 'custom':
  1431. label = ('%s' % self.parent.custompage.customstring)
  1432. self.lprojection.SetLabel(label)
  1433. def OnFinish(self, event):
  1434. dlg = wx.MessageDialog(parent=self.wizard,
  1435. message=_("Do you want to create GRASS location <%s>?") % location,
  1436. caption=_("Create new location?"),
  1437. style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
  1438. if dlg.ShowModal() == wx.ID_NO:
  1439. dlg.Destroy()
  1440. event.Veto()
  1441. else:
  1442. dlg.Destroy()
  1443. event.Skip()
  1444. class LocationWizard(wx.Object):
  1445. """
  1446. Start wizard here and finish wizard here
  1447. """
  1448. def __init__(self, parent, grassdatabase):
  1449. global coordsys
  1450. self.parent = parent
  1451. #
  1452. # define wizard image
  1453. #
  1454. # file = "loc_wizard.png"
  1455. file = "loc_wizard_qgis.png"
  1456. imagePath = os.path.join(globalvar.ETCWXDIR, "images", file)
  1457. wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
  1458. # wizbmp.Rescale(250,600)
  1459. wizbmp = wizbmp.ConvertToBitmap()
  1460. #
  1461. # get georeferencing information from tables in $GISBASE/etc
  1462. #
  1463. self.__readData()
  1464. #
  1465. # datum transform number and list of datum transforms
  1466. #
  1467. self.datumtrans = 0
  1468. self.proj4string = ''
  1469. #
  1470. # define wizard pages
  1471. #
  1472. self.wizard = wiz.Wizard(parent, id=wx.ID_ANY, title=_("Define new GRASS Location"),
  1473. bitmap=wizbmp)
  1474. self.startpage = DatabasePage(self.wizard, self, grassdatabase)
  1475. self.csystemspage = CoordinateSystemPage(self.wizard, self)
  1476. self.projpage = ProjectionsPage(self.wizard, self)
  1477. self.datumpage = DatumPage(self.wizard, self)
  1478. self.paramspage = ProjParamsPage(self.wizard,self)
  1479. self.epsgpage = EPSGPage(self.wizard, self)
  1480. self.filepage = GeoreferencedFilePage(self.wizard, self)
  1481. self.wktpage = WKTPage(self.wizard, self)
  1482. self.ellipsepage = EllipsePage(self.wizard, self)
  1483. self.custompage = CustomPage(self.wizard, self)
  1484. self.sumpage = SummaryPage(self.wizard, self)
  1485. #
  1486. # set the initial order of the pages
  1487. # (should follow the epsg line)
  1488. #
  1489. self.startpage.SetNext(self.csystemspage)
  1490. self.csystemspage.SetPrev(self.startpage)
  1491. self.csystemspage.SetNext(self.sumpage)
  1492. self.projpage.SetPrev(self.csystemspage)
  1493. self.projpage.SetNext(self.paramspage)
  1494. self.paramspage.SetPrev(self.projpage)
  1495. self.paramspage.SetNext(self.datumpage)
  1496. self.datumpage.SetPrev(self.paramspage)
  1497. self.datumpage.SetNext(self.sumpage)
  1498. self.ellipsepage.SetPrev(self.paramspage)
  1499. self.ellipsepage.SetNext(self.sumpage)
  1500. self.epsgpage.SetPrev(self.csystemspage)
  1501. self.epsgpage.SetNext(self.sumpage)
  1502. self.filepage.SetPrev(self.csystemspage)
  1503. self.filepage.SetNext(self.sumpage)
  1504. self.wktpage.SetPrev(self.csystemspage)
  1505. self.wktpage.SetNext(self.sumpage)
  1506. self.custompage.SetPrev(self.csystemspage)
  1507. self.custompage.SetNext(self.sumpage)
  1508. self.sumpage.SetPrev(self.csystemspage)
  1509. #
  1510. # do pages layout
  1511. #
  1512. self.startpage.DoLayout()
  1513. self.csystemspage.DoLayout()
  1514. self.projpage.DoLayout()
  1515. self.datumpage.DoLayout()
  1516. self.paramspage.DoLayout()
  1517. self.epsgpage.DoLayout()
  1518. self.filepage.DoLayout()
  1519. self.wktpage.DoLayout()
  1520. self.ellipsepage.DoLayout()
  1521. self.custompage.DoLayout()
  1522. self.sumpage.DoLayout()
  1523. self.wizard.FitToPage(self.datumpage)
  1524. # new location created?
  1525. self.location = None
  1526. success = False
  1527. # location created in different GIS database?
  1528. self.altdb = False
  1529. #
  1530. # run wizard...
  1531. #
  1532. if self.wizard.RunWizard(self.startpage):
  1533. msg = self.OnWizFinished()
  1534. if len(msg) < 1:
  1535. self.wizard.Destroy()
  1536. self.location = self.startpage.location
  1537. if self.altdb == False:
  1538. dlg = wx.MessageDialog(parent=self.parent,
  1539. message=_("Do you want to set the default "
  1540. "region extents and resolution now?"),
  1541. caption=_("Location <%s> created") % self.location,
  1542. style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
  1543. dlg.CenterOnScreen()
  1544. if dlg.ShowModal() == wx.ID_YES:
  1545. dlg.Destroy()
  1546. defineRegion = RegionDef(self.parent, location=self.location)
  1547. defineRegion.CenterOnScreen()
  1548. defineRegion.Show()
  1549. else:
  1550. dlg.Destroy()
  1551. else: # -> error
  1552. self.wizard.Destroy()
  1553. wx.MessageBox(parent=self.parent,
  1554. message="%s" % _("Unable to create new location. "
  1555. "Location <%(loc)s> not created.\n\n"
  1556. "Details: %(err)s") % \
  1557. { 'loc' : self.startpage.location,
  1558. 'err' : msg },
  1559. caption=_("Location wizard"),
  1560. style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1561. else:
  1562. win = wx.MessageBox(parent=self.parent,
  1563. message=_("Location wizard canceled. "
  1564. "Location not created."),
  1565. caption=_("Location wizard"))
  1566. def __readData(self):
  1567. """!Get georeferencing information from tables in $GISBASE/etc"""
  1568. # read projection and parameters
  1569. f = open(os.path.join(globalvar.ETCDIR, "proj-parms.table"), "r")
  1570. self.projections = {}
  1571. self.projdesc = {}
  1572. for line in f.readlines():
  1573. line = line.strip()
  1574. try:
  1575. proj, projdesc, params = line.split(':')
  1576. paramslist = params.split(';')
  1577. plist = []
  1578. for p in paramslist:
  1579. if p == '': continue
  1580. p1, pdefault = p.split(',')
  1581. pterm, pask = p1.split('=')
  1582. p = [pterm.strip(), pask.strip(), pdefault.strip()]
  1583. plist.append(p)
  1584. self.projections[proj.lower().strip()] = (projdesc.strip(), plist)
  1585. self.projdesc[proj.lower().strip()] = projdesc.strip()
  1586. except:
  1587. continue
  1588. f.close()
  1589. # read datum definitions
  1590. f = open(os.path.join(globalvar.ETCDIR, "datum.table"), "r")
  1591. self.datums = {}
  1592. paramslist = []
  1593. for line in f.readlines():
  1594. line = line.expandtabs(1)
  1595. line = line.strip()
  1596. if line == '' or line[0] == "#":
  1597. continue
  1598. datum, info = line.split(" ", 1)
  1599. info = info.strip()
  1600. datumdesc, params = info.split(" ", 1)
  1601. datumdesc = datumdesc.strip('"')
  1602. paramlist = params.split()
  1603. ellipsoid = paramlist.pop(0)
  1604. self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist)
  1605. f.close()
  1606. # read ellipsiod definitions
  1607. f = open(os.path.join(globalvar.ETCDIR, "ellipse.table"), "r")
  1608. self.ellipsoids = {}
  1609. for line in f.readlines():
  1610. line = line.expandtabs(1)
  1611. line = line.strip()
  1612. if line == '' or line[0] == "#":
  1613. continue
  1614. ellipse, rest = line.split(" ", 1)
  1615. rest = rest.strip('" ')
  1616. desc, params = rest.split('"', 1)
  1617. desc = desc.strip('" ')
  1618. paramslist = params.split()
  1619. self.ellipsoids[ellipse] = (desc, paramslist)
  1620. f.close()
  1621. # read projection parameter description and parsing table
  1622. f = open(os.path.join(globalvar.ETCDIR, "proj-desc.table"), "r")
  1623. self.paramdesc = {}
  1624. for line in f.readlines():
  1625. line = line.strip()
  1626. try:
  1627. pparam, datatype, proj4term, desc = line.split(':')
  1628. self.paramdesc[pparam] = (datatype, proj4term, desc)
  1629. except:
  1630. continue
  1631. f.close()
  1632. def OnWizFinished(self):
  1633. database = self.startpage.grassdatabase
  1634. location = self.startpage.location
  1635. global coordsys
  1636. msg = '' # error message (empty on success)
  1637. # location already exists?
  1638. if os.path.isdir(os.path.join(database,location)):
  1639. dlg = wx.MessageDialog(parent=self.wizard,
  1640. message="%s <%s>: %s" % \
  1641. (_("Unable to create new location"),
  1642. os.path.join(database, location),
  1643. _("Location already exists in GRASS Database.")),
  1644. caption=_("Error"),
  1645. style=wx.OK | wx.ICON_ERROR)
  1646. dlg.ShowModal()
  1647. dlg.Destroy()
  1648. return False
  1649. # current GISDbase or a new one?
  1650. current_gdb = grass.gisenv()['GISDBASE']
  1651. if current_gdb != database:
  1652. # change to new GISDbase or create new one
  1653. if os.path.isdir(database) != True:
  1654. # create new directory
  1655. os.mkdir(database)
  1656. # change to new GISDbase directory
  1657. gcmd.RunCommand('g.gisenv',
  1658. parent = self.wizard,
  1659. set='GISDBASE=%s' % database)
  1660. wx.MessageBox(parent=self.wizard,
  1661. message=_("Location <%(loc)s> will be created "
  1662. "in GIS data directory <%(dir)s>."
  1663. "You will need to change the default GIS "
  1664. "data directory in the GRASS startup screen.") % \
  1665. { 'loc' : location, 'dir' : database},
  1666. caption=_("New GIS data directory"),
  1667. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  1668. # location created in alternate GISDbase
  1669. self.altdb = True
  1670. if coordsys == "xy":
  1671. msg = self.XYCreate()
  1672. elif coordsys == "proj":
  1673. proj4string = self.CreateProj4String()
  1674. msg = self.Proj4Create(proj4string)
  1675. elif coordsys == 'custom':
  1676. msg = self.CustomCreate()
  1677. elif coordsys == "epsg":
  1678. msg = self.EPSGCreate()
  1679. elif coordsys == "file":
  1680. msg = self.FileCreate()
  1681. elif coordsys == "wkt":
  1682. msg = self.WKTCreate()
  1683. return msg
  1684. def XYCreate(self):
  1685. """!Create an XY location
  1686. @return error message (empty string on success)
  1687. """
  1688. database = self.startpage.grassdatabase
  1689. location = self.startpage.location
  1690. # create location directory and PERMANENT mapset
  1691. try:
  1692. os.mkdir(os.path.join(database, location))
  1693. os.mkdir(os.path.join(database, location, 'PERMANENT'))
  1694. # create DEFAULT_WIND and WIND files
  1695. regioninfo = ['proj: 0',
  1696. 'zone: 0',
  1697. 'north: 1',
  1698. 'south: 0',
  1699. 'east: 1',
  1700. 'west: 0',
  1701. 'cols: 1',
  1702. 'rows: 1',
  1703. 'e-w resol: 1',
  1704. 'n-s resol: 1',
  1705. 'top: 1',
  1706. 'bottom: 0',
  1707. 'cols3: 1',
  1708. 'rows3: 1',
  1709. 'depths: 1',
  1710. 'e-w resol3: 1',
  1711. 'n-s resol3: 1',
  1712. 't-b resol: 1']
  1713. defwind = open(os.path.join(database, location,
  1714. "PERMANENT", "DEFAULT_WIND"), 'w')
  1715. for param in regioninfo:
  1716. defwind.write(param + '%s' % os.linesep)
  1717. defwind.close()
  1718. shutil.copy(os.path.join(database, location, "PERMANENT", "DEFAULT_WIND"),
  1719. os.path.join(database, location, "PERMANENT", "WIND"))
  1720. # create MYNAME file
  1721. myname = open(os.path.join(database, location, "PERMANENT",
  1722. "MYNAME"), 'w')
  1723. myname.write('%s' % os.linesep)
  1724. myname.close()
  1725. except OSError, e:
  1726. return e
  1727. return ''
  1728. def CreateProj4String(self):
  1729. """!Constract PROJ.4 string"""
  1730. location = self.startpage.location
  1731. proj = self.projpage.p4proj
  1732. projdesc = self.projpage.projdesc
  1733. proj4params = self.paramspage.p4projparams
  1734. datum = self.datumpage.datum
  1735. if self.datumpage.datumdesc:
  1736. datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse
  1737. else:
  1738. datumdesc = ''
  1739. datumparams = self.datumpage.datumparams
  1740. ellipse = self.ellipsepage.ellipse
  1741. ellipsedesc = self.ellipsepage.ellipsedesc
  1742. ellipseparams = self.ellipsepage.ellipseparams
  1743. #
  1744. # creating PROJ.4 string
  1745. #
  1746. proj4string = '%s %s' % (proj, proj4params)
  1747. # set ellipsoid parameters
  1748. if ellipse != '': proj4string = '%s +ellps=%s' % (proj4string, ellipse)
  1749. for item in ellipseparams:
  1750. if item[:4] == 'f=1/':
  1751. item = ' +rf='+item[4:]
  1752. else:
  1753. item = ' +'+item
  1754. proj4string = '%s %s' % (proj4string, item)
  1755. # set datum and transform parameters if relevant
  1756. if datum != '': proj4string = '%s +datum=%s' % (proj4string, datum)
  1757. if datumparams:
  1758. for item in datumparams:
  1759. proj4string = '%s +%s' % (proj4string,item)
  1760. proj4string = '%s +no_defs' % proj4string
  1761. wx.MessageBox(proj4string, 'final proj4 string')
  1762. return proj4string
  1763. def Proj4Create(self, proj4string):
  1764. """!Create a new location for selected projection
  1765. @return error message (empty string on success)
  1766. """
  1767. ret, msg = gcmd.RunCommand('g.proj',
  1768. flags = 'c',
  1769. proj4 = proj4string,
  1770. location = self.startpage.location,
  1771. datumtrans = self.datumtrans,
  1772. getErrorMsg = True)
  1773. if ret == 0:
  1774. return ''
  1775. return msg
  1776. def CustomCreate(self):
  1777. """!Create a new location based on given proj4 string
  1778. @return error message (empty string on success)
  1779. """
  1780. proj4string = self.custompage.customstring
  1781. location = self.startpage.location
  1782. ret, msg = gcmd.RunCommand('g.proj',
  1783. flags = 'c',
  1784. proj4 = proj4string,
  1785. location = location,
  1786. getErrorMsg = True)
  1787. if ret == 0:
  1788. return ''
  1789. return msg
  1790. def EPSGCreate(self):
  1791. """!Create a new location from an EPSG code.
  1792. @return error message (empty string on success)
  1793. """
  1794. epsgcode = self.epsgpage.epsgcode
  1795. epsgdesc = self.epsgpage.epsgdesc
  1796. location = self.startpage.location
  1797. # should not happend
  1798. if epsgcode == '':
  1799. return _('EPSG code missing.')
  1800. ret, msg = gcmd.RunCommand('g.proj',
  1801. flags = 'c',
  1802. epsg = epsgcode,
  1803. location = location,
  1804. datumtrans = self.datumtrans,
  1805. getErrorMsg = True)
  1806. if ret == 0:
  1807. return ''
  1808. return msg
  1809. def FileCreate(self):
  1810. """!Create a new location from a georeferenced file
  1811. @return error message (empty string on success)
  1812. """
  1813. georeffile = self.filepage.georeffile
  1814. location = self.startpage.location
  1815. # this should not happen
  1816. if not georeffile or not os.path.isfile(georeffile):
  1817. return _("File not found.")
  1818. # creating location
  1819. ret, msg = gcmd.RunCommand('g.proj',
  1820. flags = 'c',
  1821. georef = georeffile,
  1822. location = location,
  1823. getErrorMsg = True)
  1824. if ret == 0:
  1825. return ''
  1826. return msg
  1827. def WKTCreate(self):
  1828. """!Create a new location from a WKT file
  1829. @return error message (empty string on success)
  1830. """
  1831. wktfile = self.wktpage.wktfile
  1832. location = self.startpage.location
  1833. # this should not happen
  1834. if not wktfile or not os.path.isfile(wktfile):
  1835. return _("File not found.")
  1836. # creating location
  1837. ret, msg = gcmd.RunCommand('g.proj',
  1838. flags = 'c',
  1839. wkt = wktfile,
  1840. location = location,
  1841. getErrorMsg = True)
  1842. if ret == 0:
  1843. return ''
  1844. return msg
  1845. class RegionDef(BaseClass, wx.Frame):
  1846. """
  1847. Page for setting default region extents and resolution
  1848. """
  1849. def __init__(self, parent, id=wx.ID_ANY,
  1850. title=_("Set default region extent and resolution"), location=None):
  1851. wx.Frame.__init__(self, parent, id, title, size=(650,300))
  1852. panel = wx.Panel(self, id=wx.ID_ANY)
  1853. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  1854. self.parent = parent
  1855. self.location = location
  1856. #
  1857. # default values
  1858. #
  1859. # 2D
  1860. self.north = 1.0
  1861. self.south = 0.0
  1862. self.east = 1.0
  1863. self.west = 0.0
  1864. self.nsres = 1.0
  1865. self.ewres = 1.0
  1866. # 3D
  1867. self.top = 1.0
  1868. self.bottom = 0.0
  1869. # self.nsres3 = 1.0
  1870. # self.ewres3 = 1.0
  1871. self.tbres = 1.0
  1872. #
  1873. # inputs
  1874. #
  1875. # 2D
  1876. self.tnorth = self.MakeTextCtrl(text=str(self.north), size=(150, -1), parent=panel)
  1877. self.tsouth = self.MakeTextCtrl(str(self.south), size=(150, -1), parent=panel)
  1878. self.twest = self.MakeTextCtrl(str(self.west), size=(150, -1), parent=panel)
  1879. self.teast = self.MakeTextCtrl(str(self.east), size=(150, -1), parent=panel)
  1880. self.tnsres = self.MakeTextCtrl(str(self.nsres), size=(150, -1), parent=panel)
  1881. self.tewres = self.MakeTextCtrl(str(self.ewres), size=(150, -1), parent=panel)
  1882. #
  1883. # labels
  1884. #
  1885. self.lrows = self.MakeLabel(parent=panel)
  1886. self.lcols = self.MakeLabel(parent=panel)
  1887. self.lcells = self.MakeLabel(parent=panel)
  1888. #
  1889. # buttons
  1890. #
  1891. self.bset = self.MakeButton(text=_("&Set region"), id=wx.ID_OK, parent=panel)
  1892. self.bcancel = wx.Button(panel, id=wx.ID_CANCEL)
  1893. self.bset.SetDefault()
  1894. #
  1895. # image
  1896. #
  1897. self.img = wx.Image(os.path.join(globalvar.ETCWXDIR, "images",
  1898. "qgis_world.png"), wx.BITMAP_TYPE_PNG).ConvertToBitmap()
  1899. #
  1900. # set current working environment to PERMANENT mapset
  1901. # in selected location in order to set default region (WIND)
  1902. #
  1903. envval = {}
  1904. ret = gcmd.RunCommand('g.gisenv',
  1905. read = True)
  1906. if ret:
  1907. for line in ret.splitlines():
  1908. key, val = line.split('=')
  1909. envval[key] = val
  1910. self.currlocation = envval['LOCATION_NAME'].strip("';")
  1911. self.currmapset = envval['MAPSET'].strip("';")
  1912. if self.currlocation != self.location or self.currmapset != 'PERMANENT':
  1913. gcmd.RunCommand('g.gisenv',
  1914. set = 'LOCATION_NAME=%s' % self.location)
  1915. gcmd.RunCommand('g.gisenv',
  1916. set = 'MAPSET=PERMANENT')
  1917. else:
  1918. dlg = wx.MessageBox(parent=self,
  1919. message=_('Invalid location selected.'),
  1920. caption=_("Error"), style=wx.ID_OK | wx.ICON_ERROR)
  1921. return
  1922. #
  1923. # get current region settings
  1924. #
  1925. region = {}
  1926. ret = gcmd.RunCommand('g.region',
  1927. read = True,
  1928. flags = 'gp3')
  1929. if ret:
  1930. for line in ret.splitlines():
  1931. key, val = line.split('=')
  1932. region[key] = float(val)
  1933. else:
  1934. dlg = wx.MessageBox(parent=self,
  1935. message=_("Invalid region"),
  1936. caption=_("Error"), style=wx.ID_OK | wx.ICON_ERROR)
  1937. dlg.ShowModal()
  1938. dlg.Destroy()
  1939. return
  1940. #
  1941. # update values
  1942. # 2D
  1943. self.north = float(region['n'])
  1944. self.south = float(region['s'])
  1945. self.east = float(region['e'])
  1946. self.west = float(region['w'])
  1947. self.nsres = float(region['nsres'])
  1948. self.ewres = float(region['ewres'])
  1949. self.rows = int(region['rows'])
  1950. self.cols = int(region['cols'])
  1951. self.cells = int(region['cells'])
  1952. # 3D
  1953. self.top = float(region['t'])
  1954. self.bottom = float(region['b'])
  1955. # self.nsres3 = float(region['nsres3'])
  1956. # self.ewres3 = float(region['ewres3'])
  1957. self.tbres = float(region['tbres'])
  1958. self.depth = int(region['depths'])
  1959. self.cells3 = int(region['3dcells'])
  1960. #
  1961. # 3D box collapsable
  1962. #
  1963. self.infoCollapseLabelExp = _("Click here to show 3D settings")
  1964. self.infoCollapseLabelCol = _("Click here to hide 3D settings")
  1965. self.settings3D = wx.CollapsiblePane(parent=panel,
  1966. label=self.infoCollapseLabelExp,
  1967. style=wx.CP_DEFAULT_STYLE |
  1968. wx.CP_NO_TLW_RESIZE | wx.EXPAND)
  1969. self.MakeSettings3DPaneContent(self.settings3D.GetPane())
  1970. self.settings3D.Collapse(False) # FIXME
  1971. self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSettings3DPaneChanged, self.settings3D)
  1972. #
  1973. # set current region settings
  1974. #
  1975. self.tnorth.SetValue(str(self.north))
  1976. self.tsouth.SetValue(str(self.south))
  1977. self.twest.SetValue(str(self.west))
  1978. self.teast.SetValue(str(self.east))
  1979. self.tnsres.SetValue(str(self.nsres))
  1980. self.tewres.SetValue(str(self.ewres))
  1981. self.ttop.SetValue(str(self.top))
  1982. self.tbottom.SetValue(str(self.bottom))
  1983. # self.tnsres3.SetValue(str(self.nsres3))
  1984. # self.tewres3.SetValue(str(self.ewres3))
  1985. self.ttbres.SetValue(str(self.tbres))
  1986. self.lrows.SetLabel(_("Rows: %d" % self.rows))
  1987. self.lcols.SetLabel(_("Cols: %d" % self.cols))
  1988. self.lcells.SetLabel(_("Cells: %d" % self.cells))
  1989. #
  1990. # bindings
  1991. #
  1992. self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset)
  1993. self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel)
  1994. self.tnorth.Bind(wx.EVT_TEXT, self.OnValue)
  1995. self.tsouth.Bind(wx.EVT_TEXT, self.OnValue)
  1996. self.teast.Bind(wx.EVT_TEXT, self.OnValue)
  1997. self.twest.Bind(wx.EVT_TEXT, self.OnValue)
  1998. self.tnsres.Bind(wx.EVT_TEXT, self.OnValue)
  1999. self.tewres.Bind(wx.EVT_TEXT, self.OnValue)
  2000. self.ttop.Bind(wx.EVT_TEXT, self.OnValue)
  2001. self.tbottom.Bind(wx.EVT_TEXT, self.OnValue)
  2002. # self.tnsres3.Bind(wx.EVT_TEXT, self.OnValue)
  2003. # self.tewres3.Bind(wx.EVT_TEXT, self.OnValue)
  2004. self.ttbres.Bind(wx.EVT_TEXT, self.OnValue)
  2005. self.__DoLayout(panel)
  2006. self.SetMinSize(self.GetBestSize())
  2007. self.minWindowSize = self.GetMinSize()
  2008. def MakeSettings3DPaneContent(self, pane):
  2009. """!Create 3D region settings pane"""
  2010. border = wx.BoxSizer(wx.VERTICAL)
  2011. gridSizer = wx.GridBagSizer(vgap=0, hgap=0)
  2012. # inputs
  2013. self.ttop = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.top),
  2014. size=(150, -1))
  2015. self.tbottom = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.bottom),
  2016. size=(150, -1))
  2017. self.ttbres = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.tbres),
  2018. size=(150, -1))
  2019. # self.tnsres3 = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.nsres3),
  2020. # size=(150, -1))
  2021. # self.tewres3 = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.ewres3),
  2022. # size=(150, -1))
  2023. #labels
  2024. self.ldepth = wx.StaticText(parent=pane, label=_("Depth: %d") % self.depth)
  2025. self.lcells3 = wx.StaticText(parent=pane, label=_("3D Cells: %d") % self.cells3)
  2026. # top
  2027. gridSizer.Add(item=wx.StaticText(parent=pane, label=_("Top")),
  2028. flag=wx.ALIGN_CENTER |
  2029. wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2030. pos=(0, 1))
  2031. gridSizer.Add(item=self.ttop,
  2032. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2033. wx.ALL, border=5, pos=(1, 1))
  2034. # bottom
  2035. gridSizer.Add(item=wx.StaticText(parent=pane, label=_("Bottom")),
  2036. flag=wx.ALIGN_CENTER |
  2037. wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2038. pos=(0, 2))
  2039. gridSizer.Add(item=self.tbottom,
  2040. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2041. wx.ALL, border=5, pos=(1, 2))
  2042. # tbres
  2043. gridSizer.Add(item=wx.StaticText(parent=pane, label=_("T-B resolution")),
  2044. flag=wx.ALIGN_CENTER |
  2045. wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2046. pos=(0, 3))
  2047. gridSizer.Add(item=self.ttbres,
  2048. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2049. wx.ALL, border=5, pos=(1, 3))
  2050. # res
  2051. # gridSizer.Add(item=wx.StaticText(parent=pane, label=_("3D N-S resolution")),
  2052. # flag=wx.ALIGN_CENTER |
  2053. # wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2054. # pos=(2, 1))
  2055. # gridSizer.Add(item=self.tnsres3,
  2056. # flag=wx.ALIGN_CENTER_HORIZONTAL |
  2057. # wx.ALL, border=5, pos=(3, 1))
  2058. # gridSizer.Add(item=wx.StaticText(parent=pane, label=_("3D E-W resolution")),
  2059. # flag=wx.ALIGN_CENTER |
  2060. # wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2061. # pos=(2, 3))
  2062. # gridSizer.Add(item=self.tewres3,
  2063. # flag=wx.ALIGN_CENTER_HORIZONTAL |
  2064. # wx.ALL, border=5, pos=(3, 3))
  2065. # rows/cols/cells
  2066. gridSizer.Add(item=self.ldepth,
  2067. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2068. wx.ALL, border=5, pos=(2, 1))
  2069. gridSizer.Add(item=self.lcells3,
  2070. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2071. wx.ALL, border=5, pos=(2, 2))
  2072. border.Add(item=gridSizer, proportion=1,
  2073. flag=wx.ALL | wx.ALIGN_CENTER | wx.EXPAND, border=5)
  2074. pane.SetSizer(border)
  2075. border.Fit(pane)
  2076. def OnSettings3DPaneChanged(self, event):
  2077. """!Collapse 3D settings box"""
  2078. if self.settings3D.IsExpanded():
  2079. self.settings3D.SetLabel(self.infoCollapseLabelCol)
  2080. self.Layout()
  2081. self.SetSize(self.GetBestSize())
  2082. self.SetMinSize(self.GetSize())
  2083. else:
  2084. self.settings3D.SetLabel(self.infoCollapseLabelExp)
  2085. self.Layout()
  2086. self.SetSize(self.minWindowSize)
  2087. self.SetMinSize(self.minWindowSize)
  2088. self.SendSizeEvent()
  2089. def __DoLayout(self, panel):
  2090. """!Window layout"""
  2091. frameSizer = wx.BoxSizer(wx.VERTICAL)
  2092. gridSizer = wx.GridBagSizer(vgap=0, hgap=0)
  2093. settings3DSizer = wx.BoxSizer(wx.VERTICAL)
  2094. buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
  2095. # north
  2096. gridSizer.Add(item=self.MakeLabel(text=_("North"), parent=panel),
  2097. flag=wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL |
  2098. wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(0, 2))
  2099. gridSizer.Add(item=self.tnorth,
  2100. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2101. wx.ALIGN_CENTER_VERTICAL |
  2102. wx.ALL, border=5, pos=(1, 2))
  2103. # west
  2104. gridSizer.Add(item=self.MakeLabel(text=_("West"), parent=panel),
  2105. flag=wx.ALIGN_RIGHT |
  2106. wx.ALIGN_CENTER_VERTICAL |
  2107. wx.LEFT | wx.TOP | wx.BOTTOM, border=5, pos=(2, 0))
  2108. gridSizer.Add(item=self.twest,
  2109. flag=wx.ALIGN_RIGHT |
  2110. wx.ALIGN_CENTER_VERTICAL |
  2111. wx.ALL, border=5, pos=(2, 1))
  2112. gridSizer.Add(item=wx.StaticBitmap(panel, wx.ID_ANY, self.img, (-1, -1),
  2113. (self.img.GetWidth(), self.img.GetHeight())),
  2114. flag=wx.ALIGN_CENTER |
  2115. wx.ALIGN_CENTER_VERTICAL |
  2116. wx.ALL, border=5, pos=(2, 2))
  2117. # east
  2118. gridSizer.Add(item=self.teast,
  2119. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2120. wx.ALIGN_CENTER_VERTICAL |
  2121. wx.ALL, border=5, pos=(2, 3))
  2122. gridSizer.Add(item=self.MakeLabel(text=_("East"), parent=panel),
  2123. flag=wx.ALIGN_LEFT |
  2124. wx.ALIGN_CENTER_VERTICAL |
  2125. wx.RIGHT | wx.TOP | wx.BOTTOM, border=5, pos=(2, 4))
  2126. # south
  2127. gridSizer.Add(item=self.tsouth,
  2128. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2129. wx.ALIGN_CENTER_VERTICAL |
  2130. wx.ALL, border=5, pos=(3, 2))
  2131. gridSizer.Add(item=self.MakeLabel(text=_("South"), parent=panel),
  2132. flag=wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL |
  2133. wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5, pos=(4, 2))
  2134. # ns-res
  2135. gridSizer.Add(item=self.MakeLabel(text=_("N-S resolution"), parent=panel),
  2136. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2137. wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(5, 1))
  2138. gridSizer.Add(item=self.tnsres,
  2139. flag=wx.ALIGN_RIGHT |
  2140. wx.ALIGN_CENTER_VERTICAL |
  2141. wx.ALL, border=5, pos=(6, 1))
  2142. # ew-res
  2143. gridSizer.Add(item=self.MakeLabel(text=_("E-W resolution"), parent=panel),
  2144. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2145. wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(5, 3))
  2146. gridSizer.Add(item=self.tewres,
  2147. flag=wx.ALIGN_RIGHT |
  2148. wx.ALIGN_CENTER_VERTICAL |
  2149. wx.ALL, border=5, pos=(6, 3))
  2150. # rows/cols/cells
  2151. gridSizer.Add(item=self.lrows,
  2152. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2153. wx.ALL, border=5, pos=(7, 1))
  2154. gridSizer.Add(item=self.lcells,
  2155. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2156. wx.ALL, border=5, pos=(7, 2))
  2157. gridSizer.Add(item=self.lcols,
  2158. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2159. wx.ALL, border=5, pos=(7, 3))
  2160. # 3D
  2161. settings3DSizer.Add(item=self.settings3D,
  2162. flag=wx.ALL,
  2163. border=5)
  2164. # buttons
  2165. buttonSizer.Add(item=self.bcancel, proportion=1,
  2166. flag=wx.ALIGN_RIGHT |
  2167. wx.ALIGN_CENTER_VERTICAL |
  2168. wx.ALL, border=10)
  2169. buttonSizer.Add(item=self.bset, proportion=1,
  2170. flag=wx.ALIGN_CENTER |
  2171. wx.ALIGN_CENTER_VERTICAL |
  2172. wx.ALL, border=10)
  2173. frameSizer.Add(item=gridSizer, proportion=1,
  2174. flag=wx.ALL | wx.ALIGN_CENTER, border=5)
  2175. frameSizer.Add(item=settings3DSizer, proportion=0,
  2176. flag=wx.ALL | wx.ALIGN_CENTER, border=5)
  2177. frameSizer.Add(item=buttonSizer, proportion=0,
  2178. flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
  2179. self.SetAutoLayout(True)
  2180. panel.SetSizer(frameSizer)
  2181. frameSizer.Fit(panel)
  2182. self.Layout()
  2183. def OnValue(self, event):
  2184. """!Set given value"""
  2185. try:
  2186. if event.GetId() == self.tnorth.GetId():
  2187. self.north = float(event.GetString())
  2188. elif event.GetId() == self.tsouth.GetId():
  2189. self.south = float(event.GetString())
  2190. elif event.GetId() == self.teast.GetId():
  2191. self.east = float(event.GetString())
  2192. elif event.GetId() == self.twest.GetId():
  2193. self.west = float(event.GetString())
  2194. elif event.GetId() == self.tnsres.GetId():
  2195. self.nsres = float(event.GetString())
  2196. elif event.GetId() == self.tewres.GetId():
  2197. self.ewres = float(event.GetString())
  2198. elif event.GetId() == self.ttop.GetId():
  2199. self.top = float(event.GetString())
  2200. elif event.GetId() == self.tbottom.GetId():
  2201. self.bottom = float(event.GetString())
  2202. # elif event.GetId() == self.tnsres3.GetId():
  2203. # self.nsres3 = float(event.GetString())
  2204. # elif event.GetId() == self.tewres3.GetId():
  2205. # self.ewres3 = float(event.GetString())
  2206. elif event.GetId() == self.ttbres.GetId():
  2207. self.tbres = float(event.GetString())
  2208. self.__UpdateInfo()
  2209. except ValueError, e:
  2210. if len(event.GetString()) > 0 and event.GetString() != '-':
  2211. dlg = wx.MessageBox(parent=self,
  2212. message=_("Invalid value: %s") % e,
  2213. caption=_("Error"),
  2214. style=wx.OK | wx.ICON_ERROR)
  2215. # reset values
  2216. self.tnorth.SetValue(str(self.north))
  2217. self.tsouth.SetValue(str(self.south))
  2218. self.teast.SetValue(str(self.east))
  2219. self.twest.SetValue(str(self.west))
  2220. self.tnsres.SetValue(str(self.nsres))
  2221. self.tewres.SetValue(str(self.ewres))
  2222. self.ttop.SetValue(str(self.top))
  2223. self.tbottom.SetValue(str(self.bottom))
  2224. self.ttbres.SetValue(str(self.tbres))
  2225. # self.tnsres3.SetValue(str(self.nsres3))
  2226. # self.tewres3.SetValue(str(self.ewres3))
  2227. event.Skip()
  2228. def __UpdateInfo(self):
  2229. """!Update number of rows/cols/cells"""
  2230. self.rows = int((self.north - self.south) / self.nsres)
  2231. self.cols = int((self.east - self.west) / self.ewres)
  2232. self.cells = self.rows * self.cols
  2233. self.depth = int((self.top - self.bottom) / self.tbres)
  2234. self.cells3 = self.rows * self.cols * self.depth
  2235. # 2D
  2236. self.lrows.SetLabel(_("Rows: %d") % self.rows)
  2237. self.lcols.SetLabel(_("Cols: %d") % self.cols)
  2238. self.lcells.SetLabel(_("Cells: %d") % self.cells)
  2239. # 3D
  2240. self.ldepth.SetLabel(_("Depth: %d" % self.depth))
  2241. self.lcells3.SetLabel(_("3D Cells: %d" % self.cells3))
  2242. def OnSetButton(self, event=None):
  2243. """!Set default region"""
  2244. ret = gcmd.RunCommand('g.region',
  2245. flags = 'sgpa',
  2246. n = self.north,
  2247. s = self.south,
  2248. e = self.east,
  2249. w = self.west,
  2250. nsres = self.nsres,
  2251. ewres = self.ewres,
  2252. t = self.top,
  2253. b = self.bottom,
  2254. tbres = self.tbres)
  2255. if ret == 0:
  2256. self.Destroy()
  2257. def OnCancel(self, event):
  2258. self.Destroy()
  2259. class TransList(wx.VListBox):
  2260. """!Creates a multiline listbox for selecting datum transforms"""
  2261. def OnDrawItem(self, dc, rect, n):
  2262. if self.GetSelection() == n:
  2263. c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
  2264. else:
  2265. c = self.GetForegroundColour()
  2266. dc.SetFont(self.GetFont())
  2267. dc.SetTextForeground(c)
  2268. dc.DrawLabel(self._getItemText(n), rect,
  2269. wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  2270. def OnMeasureItem(self, n):
  2271. height = 0
  2272. if self._getItemText(n) == None: return
  2273. for line in self._getItemText(n).splitlines():
  2274. w, h = self.GetTextExtent(line)
  2275. height += h
  2276. return height + 5
  2277. def _getItemText(self, item):
  2278. global transformlist
  2279. transitem = transformlist[item]
  2280. if transitem.strip() !='':
  2281. return transitem
  2282. class SelectTransformDialog(wx.Dialog):
  2283. """!Dialog for selecting datum transformations"""
  2284. def __init__(self, parent, transforms, title=_("Select datum transformation"),
  2285. pos=wx.DefaultPosition, size=wx.DefaultSize,
  2286. style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
  2287. wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
  2288. global transformlist
  2289. self.CentreOnParent()
  2290. # default transform number
  2291. self.transnum = 0
  2292. panel = scrolled.ScrolledPanel(self, wx.ID_ANY)
  2293. sizer = wx.BoxSizer(wx.VERTICAL)
  2294. #
  2295. # set panel sizer
  2296. #
  2297. panel.SetSizer(sizer)
  2298. panel.SetupScrolling()
  2299. #
  2300. # dialog body
  2301. #
  2302. bodyBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
  2303. label=" %s " % _("Select from list of datum transformations"))
  2304. bodySizer = wx.StaticBoxSizer(bodyBox)
  2305. # add no transform option
  2306. transforms = '---\n\n0\nDo not apply any datum transformations\n\n' + transforms
  2307. transformlist = transforms.split('---')
  2308. tlistlen = len(transformlist)
  2309. # calculate size for transform list
  2310. height = 0
  2311. width = 0
  2312. for line in transforms.splitlines():
  2313. w, h = self.GetTextExtent(line)
  2314. height += h
  2315. width = max(width, w)
  2316. height = height + 5
  2317. if height > 400: height = 400
  2318. width = width + 5
  2319. if width > 400: width = 400
  2320. #
  2321. # VListBox for displaying and selecting transformations
  2322. #
  2323. self.translist = TransList(panel, id=-1, size=(width, height), style=wx.SUNKEN_BORDER)
  2324. self.translist.SetItemCount(tlistlen)
  2325. self.translist.SetSelection(2)
  2326. self.translist.SetFocus()
  2327. self.Bind(wx.EVT_LISTBOX, self.ClickTrans, self.translist)
  2328. bodySizer.Add(item=self.translist, proportion=1, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
  2329. #
  2330. # buttons
  2331. #
  2332. btnsizer = wx.StdDialogButtonSizer()
  2333. btn = wx.Button(parent=panel, id=wx.ID_OK)
  2334. btn.SetDefault()
  2335. btnsizer.AddButton(btn)
  2336. btn = wx.Button(parent=panel, id=wx.ID_CANCEL)
  2337. btnsizer.AddButton(btn)
  2338. btnsizer.Realize()
  2339. sizer.Add(item=bodySizer, proportion=1,
  2340. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  2341. sizer.Add(item=btnsizer, proportion=0,
  2342. flag= wx.ALL | wx.ALIGN_RIGHT, border=5)
  2343. sizer.Fit(panel)
  2344. self.SetSize(self.GetBestSize())
  2345. self.Layout()
  2346. def ClickTrans(self, event):
  2347. """!Get the number of the datum transform to use in g.proj"""
  2348. self.transnum = event.GetSelection()
  2349. self.transnum = self.transnum - 1
  2350. def GetTransform(self):
  2351. """!Get the number of the datum transform to use in g.proj"""
  2352. self.transnum = self.translist.GetSelection()
  2353. self.transnum = self.transnum - 1
  2354. return self.transnum
  2355. if __name__ == "__main__":
  2356. app = wx.PySimpleApp()
  2357. # gWizard = LocationWizard(None, "")
  2358. gWizard = RegionDef(None)
  2359. gWizzard.Show()
  2360. app.MainLoop()