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