location_wizard.py 104 KB

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