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