location_wizard.py 102 KB

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