location_wizard.py 99 KB

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