location_wizard.py 101 KB

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