GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
wizard.py
Go to the documentation of this file.
00001 """!
00002 @package location_wizard.wizard
00003 
00004 @brief Location wizard - creates a new GRASS Location. User can choose
00005 from multiple methods.
00006 
00007 Classes:
00008  - wizard::TitledPage
00009  - wizard::DatabasePage
00010  - wizard::CoordinateSystemPage
00011  - wizard::ProjectionsPage
00012  - wizard::ItemList
00013  - wizard::ProjParamsPage
00014  - wizard::DatumPage
00015  - wizard::EllipsePage
00016  - wizard::GeoreferencedFilePage
00017  - wizard::WKTPage
00018  - wizard::EPSGPage
00019  - wizard::CustomPage
00020  - wizard::SummaryPage
00021  - wizard::LocationWizard
00022 
00023 (C) 2007-2011 by the GRASS Development Team
00024 
00025 This program is free software under the GNU General Public License
00026 (>=v2). Read the file COPYING that comes with GRASS for details.
00027 
00028 @author Michael Barton
00029 @author Jachym Cepicky
00030 @author Martin Landa <landa.martin gmail.com>   
00031 """
00032 import os
00033 import locale
00034 
00035 import wx
00036 import wx.lib.mixins.listctrl as listmix
00037 import wx.wizard as wiz
00038 import wx.lib.scrolledpanel as scrolled
00039 
00040 from core                    import globalvar
00041 from core                    import utils
00042 from core.gcmd               import RunCommand, GError, GMessage, GWarning
00043 from location_wizard.base    import BaseClass
00044 from location_wizard.dialogs import RegionDef, SelectTransformDialog
00045 
00046 from grass.script import core as grass
00047 
00048 global coordsys
00049 global north
00050 global south
00051 global east
00052 global west
00053 global resolution
00054 global wizerror
00055 global translist
00056 
00057 class TitledPage(BaseClass, wiz.WizardPageSimple):
00058     """!Class to make wizard pages. Generic methods to make labels,
00059     text entries, and buttons.
00060     """
00061     def __init__(self, parent, title):
00062 
00063         self.page = wiz.WizardPageSimple.__init__(self, parent)
00064 
00065         # page title
00066         self.title = wx.StaticText(parent = self, id = wx.ID_ANY, label = title)
00067         self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
00068 
00069         # main sizers
00070         self.pagesizer = wx.BoxSizer(wx.VERTICAL)
00071         self.sizer = wx.GridBagSizer(vgap = 0, hgap = 0)
00072         
00073     def DoLayout(self):
00074         """!Do page layout"""
00075         self.pagesizer.Add(item = self.title, proportion = 0,
00076                            flag = wx.ALIGN_CENTRE | wx.ALL,
00077                            border = 5)
00078         self.pagesizer.Add(item = wx.StaticLine(self, -1), proportion = 0,
00079                            flag = wx.EXPAND | wx.ALL,
00080                            border = 0)
00081         self.pagesizer.Add(item = self.sizer, proportion = 1,
00082                            flag = wx.EXPAND)
00083         
00084         self.SetAutoLayout(True)
00085         self.SetSizer(self.pagesizer)
00086         self.Layout()
00087 
00088 class DatabasePage(TitledPage):
00089     """!Wizard page for setting GIS data directory and location name"""
00090     def __init__(self, wizard, parent, grassdatabase):
00091         TitledPage.__init__(self, wizard, _("Define GRASS Database and Location Name"))
00092 
00093         self.grassdatabase  = grassdatabase
00094         self.location       = ''
00095         self.locTitle       = ''
00096         
00097         # buttons
00098         self.bbrowse = self.MakeButton(_("Browse"))
00099 
00100         # text controls
00101         self.tgisdbase = self.MakeTextCtrl(grassdatabase, size = (300, -1))
00102         self.tlocation = self.MakeTextCtrl("newLocation", size = (300, -1))
00103         self.tlocTitle = self.MakeTextCtrl(size = (400, -1))
00104         
00105         # layout
00106         self.sizer.AddGrowableCol(3)
00107         self.sizer.Add(item = self.MakeLabel(_("GIS Data Directory:")),
00108                        flag = wx.ALIGN_RIGHT |
00109                        wx.ALIGN_CENTER_VERTICAL |
00110                        wx.ALL, border = 5,
00111                        pos = (1, 1))
00112         self.sizer.Add(item = self.tgisdbase,
00113                        flag = wx.ALIGN_LEFT |
00114                        wx.ALIGN_CENTER_VERTICAL |
00115                        wx.ALL, border = 5,
00116                        pos = (1, 2))
00117         self.sizer.Add(item = self.bbrowse,
00118                        flag = wx.ALIGN_LEFT |
00119                        wx.ALIGN_CENTER_VERTICAL |
00120                        wx.ALL, border = 5,
00121                        pos = (1, 3))
00122         
00123         self.sizer.Add(item = self.MakeLabel("%s:" % _("Project Location")),
00124                        flag = wx.ALIGN_RIGHT |
00125                        wx.ALIGN_CENTER_VERTICAL |
00126                        wx.ALL, border = 5,
00127                        pos = (2, 1))
00128         self.sizer.Add(item = self.tlocation,
00129                        flag = wx.ALIGN_LEFT |
00130                        wx.ALIGN_CENTER_VERTICAL |
00131                        wx.ALL, border = 5,
00132                        pos = (2, 2))
00133 
00134         self.sizer.Add(item = self.MakeLabel("%s:" % _("Location Title")),
00135                        flag = wx.ALIGN_RIGHT |
00136                        wx.ALIGN_TOP | wx.ALIGN_CENTER_VERTICAL |
00137                        wx.ALL, border = 5,
00138                        pos = (3, 1))
00139         self.sizer.Add(item = self.tlocTitle,
00140                        flag = wx.ALIGN_LEFT |
00141                        wx.ALIGN_CENTER_VERTICAL |
00142                        wx.ALL, border = 5,
00143                        pos = (3, 2), span  =  (1, 2))
00144         
00145         # bindings
00146         self.Bind(wx.EVT_BUTTON,                self.OnBrowse, self.bbrowse)
00147         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
00148         self.tgisdbase.Bind(wx.EVT_TEXT,        self.OnChangeName)
00149         self.tlocation.Bind(wx.EVT_TEXT,        self.OnChangeName)
00150         
00151     def OnChangeName(self, event):
00152         """!Name for new location was changed"""
00153         nextButton = wx.FindWindowById(wx.ID_FORWARD)
00154         if len(event.GetString()) > 0:
00155             if not nextButton.IsEnabled():
00156                 nextButton.Enable()
00157         else:
00158             nextButton.Disable()
00159 
00160         event.Skip()
00161 
00162     def OnBrowse(self, event):
00163         """!Choose GRASS data directory"""
00164         dlg = wx.DirDialog(self, _("Choose GRASS data directory:"),
00165                            os.getcwd(), wx.DD_DEFAULT_STYLE)
00166         if dlg.ShowModal() == wx.ID_OK:
00167             self.grassdatabase = dlg.GetPath()
00168             self.tgisdbase.SetValue(self.grassdatabase)
00169             
00170         dlg.Destroy()
00171 
00172     def OnPageChanging(self, event = None):
00173         error = None
00174         if os.path.isdir(os.path.join(self.tgisdbase.GetValue(), self.tlocation.GetValue())):
00175             error = _("Location already exists in GRASS Database.")
00176 
00177         if error:
00178             GError(parent = self,
00179                    message="%s <%s>.%s%s" % (_("Unable to create location"),
00180                                              str(self.tlocation.GetValue()),
00181                                              os.linesep,
00182                                              error))
00183             event.Veto()
00184             return
00185 
00186         self.location      = self.tlocation.GetValue()
00187         self.grassdatabase = self.tgisdbase.GetValue()
00188         self.locTitle      = self.tlocTitle.GetValue()
00189         if os.linesep in self.locTitle or \
00190                 len(self.locTitle) > 255:
00191             GWarning(parent = self,
00192                      message = _("Title of the location is limited only to one line and "
00193                                  "256 characters. The rest of the text will be ignored."))
00194             self.locTitle = self.locTitle.split(os.linesep)[0][:255]
00195             
00196 class CoordinateSystemPage(TitledPage):
00197     """!Wizard page for choosing method for location creation"""
00198     def __init__(self, wizard, parent):
00199         TitledPage.__init__(self, wizard, _("Choose method for creating a new location"))
00200         
00201         self.parent = parent
00202         global coordsys
00203         
00204         # toggles
00205         self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00206                                      label = _("Select coordinate system parameters from a list"),
00207                                      style  =  wx.RB_GROUP)
00208         self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00209                                      label = _("Select EPSG code of spatial reference system"))
00210         self.radio3 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00211                                      label = _("Read projection and datum terms from a "
00212                                              "georeferenced data file"))
00213         self.radio4 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00214                                      label = _("Read projection and datum terms from a "
00215                                              "WKT or PRJ file"))
00216         self.radio5 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00217                                      label = _("Specify projection and datum terms using custom "
00218                                              "PROJ.4 parameters"))
00219         self.radio6 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00220                                      label = _("Create a generic Cartesian coordinate system (XY)"))
00221         
00222         # layout
00223         self.sizer.AddGrowableCol(1)
00224         self.sizer.SetVGap(10)
00225         self.sizer.Add(item = self.radio1,
00226                        flag = wx.ALIGN_LEFT, pos = (1, 1))
00227         self.sizer.Add(item = self.radio2,
00228                        flag = wx.ALIGN_LEFT, pos = (2, 1))
00229         self.sizer.Add(item = self.radio3,
00230                        flag = wx.ALIGN_LEFT, pos = (3, 1))
00231         self.sizer.Add(item = self.radio4,
00232                        flag = wx.ALIGN_LEFT, pos = (4, 1))
00233         self.sizer.Add(item = self.radio5,
00234                        flag = wx.ALIGN_LEFT, pos = (5, 1))
00235         self.sizer.Add(item = self.radio6,
00236                        flag = wx.ALIGN_LEFT, pos = (6, 1))
00237 
00238         # bindings
00239         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
00240         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
00241         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio3.GetId())
00242         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio4.GetId())
00243         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio5.GetId())
00244         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio6.GetId())
00245         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
00246         
00247     def OnEnterPage(self, event):
00248         global coordsys
00249         
00250         if not coordsys:
00251             coordsys = "proj"
00252             self.radio1.SetValue(True)
00253         else:
00254             if coordsys == 'proj':
00255                 self.radio1.SetValue(True)
00256             if coordsys == "epsg":
00257                 self.radio2.SetValue(True)
00258             if coordsys == "file":
00259                 self.radio3.SetValue(True)
00260             if coordsys == "wkt":
00261                 self.radio4.SetValue(True)
00262             if coordsys == "custom":
00263                 self.radio5.SetValue(True)
00264             if coordsys == "xy":
00265                 self.radio6.SetValue(True)
00266         
00267         if event.GetDirection():
00268             if coordsys == 'proj':
00269                 self.SetNext(self.parent.projpage)
00270                 self.parent.sumpage.SetPrev(self.parent.datumpage)
00271             if coordsys == "epsg":
00272                 self.SetNext(self.parent.epsgpage)
00273                 self.parent.sumpage.SetPrev(self.parent.epsgpage)
00274             if coordsys == "file":
00275                 self.SetNext(self.parent.filepage)
00276                 self.parent.sumpage.SetPrev(self.parent.filepage)
00277             if coordsys == "wkt":
00278                 self.SetNext(self.parent.wktpage)
00279                 self.parent.sumpage.SetPrev(self.parent.wktpage)
00280             if coordsys == "custom":
00281                 self.SetNext(self.parent.custompage)
00282                 self.parent.sumpage.SetPrev(self.parent.custompage)
00283             if coordsys == "xy":
00284                 self.SetNext(self.parent.sumpage)
00285                 self.parent.sumpage.SetPrev(self.parent.csystemspage)
00286         
00287         if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
00288             wx.FindWindowById(wx.ID_FORWARD).Enable()
00289     
00290     def SetVal(self, event):
00291         """!Choose method"""
00292         global coordsys
00293         if event.GetId() == self.radio1.GetId():
00294             coordsys = "proj"
00295             self.SetNext(self.parent.projpage)
00296             self.parent.sumpage.SetPrev(self.parent.datumpage)
00297         elif event.GetId() == self.radio2.GetId():
00298             coordsys = "epsg"
00299             self.SetNext(self.parent.epsgpage)
00300             self.parent.sumpage.SetPrev(self.parent.epsgpage)
00301         elif event.GetId() == self.radio3.GetId():
00302             coordsys = "file"
00303             self.SetNext(self.parent.filepage)
00304             self.parent.sumpage.SetPrev(self.parent.filepage)
00305         elif event.GetId() == self.radio4.GetId():
00306             coordsys = "wkt"
00307             self.SetNext(self.parent.wktpage)
00308             self.parent.sumpage.SetPrev(self.parent.wktpage)
00309         elif event.GetId() == self.radio5.GetId():
00310             coordsys = "custom"
00311             self.SetNext(self.parent.custompage)
00312             self.parent.sumpage.SetPrev(self.parent.custompage)
00313         elif event.GetId() == self.radio6.GetId():
00314             coordsys = "xy"
00315             self.SetNext(self.parent.sumpage)
00316             self.parent.sumpage.SetPrev(self.parent.csystemspage)
00317 
00318 class ProjectionsPage(TitledPage):
00319     """!Wizard page for selecting projection (select coordinate system option)"""
00320     def __init__(self, wizard, parent):
00321         TitledPage.__init__(self, wizard, _("Choose projection"))
00322 
00323         self.parent = parent
00324         self.proj = ''
00325         self.projdesc = ''
00326         self.p4proj = ''
00327 
00328         # text input
00329         self.tproj = self.MakeTextCtrl("", size = (200,-1))
00330         
00331         # search box
00332         self.searchb = wx.SearchCtrl(self, size = (200,-1),
00333                                      style = wx.TE_PROCESS_ENTER)
00334 
00335         # projection list
00336         self.projlist = ItemList(self, data = self.parent.projdesc.items(),
00337                                  columns = [_('Code'), _('Description')])
00338         self.projlist.resizeLastColumn(30) 
00339 
00340         # layout
00341         self.sizer.AddGrowableCol(3)
00342         self.sizer.Add(item = self.MakeLabel(_("Projection code:")),
00343                        flag = wx.ALIGN_LEFT |
00344                        wx.ALIGN_CENTER_VERTICAL |
00345                        wx.ALL, border = 5, pos = (1, 1))
00346         self.sizer.Add(item = self.tproj,
00347                        flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
00348                        border = 5, pos = (1, 2))
00349 
00350         self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
00351                        flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
00352                        border = 5, pos = (2, 1))
00353         self.sizer.Add(item = self.searchb,
00354                        flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
00355                        border = 5, pos = (2, 2))
00356         
00357         self.sizer.AddGrowableRow(3)
00358         self.sizer.Add(item = self.projlist,
00359                        flag = wx.EXPAND |
00360                        wx.ALIGN_LEFT |
00361                        wx.ALL, border = 5, pos = (3, 1), span = (1, 3))
00362 
00363         # events
00364         self.tproj.Bind(wx.EVT_TEXT, self.OnText)
00365         self.tproj.Bind(wx.EVT_TEXT_ENTER, self.OnText)
00366         self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
00367         self.projlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
00368         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
00369         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
00370         
00371     def OnPageChanging(self,event):
00372         if event.GetDirection() and self.proj not in self.parent.projections.keys():
00373             event.Veto()
00374 
00375     def OnText(self, event):
00376         """!Projection name changed"""
00377         self.proj = event.GetString().lower()
00378         self.p4proj = ''
00379         nextButton = wx.FindWindowById(wx.ID_FORWARD)
00380         if self.proj not in self.parent.projections.keys() and nextButton.IsEnabled():
00381             nextButton.Enable(False)
00382         
00383         if self.proj in self.parent.projections.keys():
00384             if self.proj == 'stp':
00385                 wx.MessageBox('Currently State Plane projections must be selected using the '
00386                               'text-based setup (g.setproj), or entered by EPSG code or '
00387                               'custom PROJ.4 terms.',
00388                               'Warning', wx.ICON_WARNING)
00389                 self.proj = ''
00390                 self.tproj.SetValue(self.proj)
00391                 nextButton.Enable(False)
00392                 return
00393             elif self.proj.lower() == 'll':
00394                 self.p4proj = '+proj=longlat'
00395             else:
00396                 self.p4proj = '+proj=' + self.proj.lower()
00397             self.projdesc = self.parent.projections[self.proj][0]
00398             nextButton.Enable()
00399 
00400     def OnEnterPage(self, event):
00401         if len(self.proj) == 0:
00402             # disable 'next' button by default
00403             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
00404         else:
00405             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
00406 
00407         event.Skip()
00408     
00409     def OnSearch(self, event):
00410         """!Search projection by desc"""
00411         str = event.GetString()
00412         try:
00413             self.proj, self.projdesc = self.projlist.Search(index = [0,1], pattern = event.GetString())
00414         except:
00415             self.proj = self.projdesc = ''
00416             
00417         event.Skip()
00418 
00419     def OnItemSelected(self, event):
00420         """!Projection selected"""
00421         index = event.m_itemIndex
00422 
00423         # set values
00424         self.proj = self.projlist.GetItem(index, 0).GetText().lower()
00425         self.tproj.SetValue(self.proj)
00426         
00427         event.Skip()
00428 
00429 class ItemList(wx.ListCtrl,
00430                listmix.ListCtrlAutoWidthMixin,
00431                listmix.ColumnSorterMixin):
00432     """!Generic list (for projections, ellipsoids, etc.)"""
00433 
00434     def __init__(self, parent, columns, data = None):
00435         wx.ListCtrl.__init__(self, parent = parent, id = wx.ID_ANY,
00436                              style = wx.LC_REPORT |
00437                              wx.LC_VIRTUAL | 
00438                              wx.LC_HRULES |
00439                              wx.LC_VRULES |
00440                              wx.LC_SINGLE_SEL |
00441                              wx.LC_SORT_ASCENDING, size = (550, 125))
00442 
00443         # original data or None
00444         self.sourceData = data
00445         
00446         #
00447         # insert columns
00448         #
00449         i = 0
00450         for column in columns:
00451             self.InsertColumn(i, column)
00452             i += 1
00453 
00454         if self.sourceData:
00455             self.Populate()
00456         
00457         for i in range(self.GetColumnCount()):
00458             self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
00459             if self.GetColumnWidth(i) < 80:
00460                 self.SetColumnWidth(i, 80)
00461         
00462         #
00463         # listmix
00464         #
00465         listmix.ListCtrlAutoWidthMixin.__init__(self)
00466         listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())
00467             
00468         #
00469         # add some attributes
00470         #
00471         self.attr1 = wx.ListItemAttr()
00472         self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
00473         self.attr2 = wx.ListItemAttr()
00474         self.attr2.SetBackgroundColour("white")
00475         self.il = wx.ImageList(16, 16)
00476         self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,   wx.ART_TOOLBAR,
00477                                                           (16,16)))
00478         self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
00479                                                           (16,16)))
00480         self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
00481 
00482         #
00483         # sort by first column
00484         #
00485         if self.sourceData:
00486             self.SortListItems(col = 0, ascending = True)
00487 
00488         #
00489         # bindings
00490         #
00491         self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick)
00492 
00493     def Populate(self, data = None, update = False):
00494         """!Populate list"""
00495         self.itemDataMap  = {}
00496         self.itemIndexMap = []
00497         
00498         if data is None:
00499             data = self.sourceData
00500         elif update:
00501             self.sourceData = data
00502 
00503         try:
00504             data.sort()
00505             self.DeleteAllItems()
00506             row = 0
00507             for value in data:
00508                 self.itemDataMap[row] = [value[0]]
00509                 for i in range(1, len(value)):
00510                      self.itemDataMap[row].append(value[i])
00511                 self.itemIndexMap.append(row)
00512                 row += 1
00513 
00514             self.SetItemCount(row)
00515             
00516             # set column width
00517             self.SetColumnWidth(0, 80)
00518             self.SetColumnWidth(1, 300)
00519             
00520             self.SendSizeEvent()
00521             
00522         except StandardError, e:
00523             wx.MessageBox(parent = self,
00524                           message = _("Unable to read list: %s") % e,
00525                           caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
00526 
00527     def OnColumnClick(self, event):
00528         """!Sort by column"""
00529         self._col = event.GetColumn()
00530 
00531         # remove duplicated arrow symbol from column header
00532         # FIXME: should be done automatically
00533         info = wx.ListItem()
00534         info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
00535         info.m_image = -1
00536         for column in range(self.GetColumnCount()):
00537             info.m_text = self.GetColumn(column).GetText()
00538             self.SetColumn(column, info)
00539 
00540         event.Skip()
00541 
00542     def GetSortImages(self):
00543         """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
00544         return (self.sm_dn, self.sm_up)
00545 
00546     def OnGetItemText(self, item, col):
00547         """!Get item text"""
00548         index = self.itemIndexMap[item]
00549         s = str(self.itemDataMap[index][col])
00550         return s
00551 
00552     def OnGetItemAttr(self, item):
00553         """!Get item attributes"""
00554         index = self.itemIndexMap[item]
00555         if ( index % 2) == 0:
00556             return self.attr2
00557         else:
00558             return self.attr1
00559 
00560     def SortItems(self, sorter = cmp):
00561         """!Sort items"""
00562         items = list(self.itemDataMap.keys())
00563         items.sort(self.Sorter)
00564         self.itemIndexMap = items
00565 
00566         # redraw the list
00567         self.Refresh()
00568         
00569     def Sorter(self, key1, key2):
00570         colName = self.GetColumn(self._col).GetText()
00571         ascending = self._colSortFlag[self._col]
00572         # convert always string
00573         item1 = self.itemDataMap[key1][self._col]
00574         item2 = self.itemDataMap[key2][self._col]
00575 
00576         if type(item1) == type('') or type(item2) == type(''):
00577             cmpVal = locale.strcoll(str(item1), str(item2))
00578         else:
00579             cmpVal = cmp(item1, item2)
00580 
00581 
00582         # If the items are equal then pick something else to make the sort value unique
00583         if cmpVal == 0:
00584             cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
00585 
00586         if ascending:
00587             return cmpVal
00588         else:
00589             return -cmpVal
00590 
00591     def GetListCtrl(self):
00592         """!Used by listmix.ColumnSorterMixin"""
00593         return self
00594 
00595     def Search (self, index, pattern):
00596         """!Search projection by description
00597         Return first found item or None
00598         """
00599         if pattern == '':
00600             self.Populate(self.sourceData)
00601             return []
00602 
00603         data = []
00604         pattern = pattern.lower()
00605         for i in range(len(self.sourceData)):
00606             for idx in index:
00607                 try:
00608                     value = str(self.sourceData[i][idx]).lower()
00609                     if pattern in value:
00610                         data.append(self.sourceData[i])
00611                         break
00612                 except UnicodeDecodeError:
00613                     # osgeo4w problem (should be fixed)
00614                     pass
00615 
00616         self.Populate(data)
00617         if len(data) > 0:
00618             return data[0]
00619         else:
00620             return []
00621 
00622 class ProjParamsPage(TitledPage):
00623     """!Wizard page for selecting method of setting coordinate system
00624     parameters (select coordinate system option)
00625     """
00626     def __init__(self, wizard, parent):
00627         TitledPage.__init__(self, wizard, _("Choose projection parameters"))
00628         global coordsys
00629         
00630         self.parent = parent
00631         self.panel = None
00632         self.prjParamSizer = None
00633         
00634         self.pparam = dict()
00635         
00636         self.p4projparams = ''
00637         self.projdesc = ''
00638 
00639         self.sizer.AddGrowableCol(1)
00640         self.sizer.AddGrowableRow(1)
00641 
00642         radioSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
00643                                  label = " %s " % _("Select datum or ellipsoid (next page)"))
00644         radioSBSizer = wx.StaticBoxSizer(radioSBox)
00645         self.sizer.Add(item = radioSBSizer, pos = (0, 1),
00646                        flag = wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border = 10)
00647         
00648         self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY, 
00649                                      label = _("Datum with associated ellipsoid"),
00650                                      style  =  wx.RB_GROUP)
00651         self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00652                                      label = _("Ellipsoid only"))   
00653         
00654         # default button setting
00655         if self.radio1.GetValue() == False and self.radio2.GetValue() == False:
00656             self.radio1.SetValue(True)
00657             self.SetNext(self.parent.datumpage)
00658             #            self.parent.sumpage.SetPrev(self.parent.datumpage)  
00659         
00660         radioSBSizer.Add(item = self.radio1,
00661                          flag = wx.ALIGN_LEFT | wx.RIGHT, border = 20)
00662         radioSBSizer.Add(item = self.radio2,
00663                          flag = wx.ALIGN_LEFT)
00664         
00665         # bindings
00666         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
00667         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
00668         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange)
00669         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
00670         
00671     def OnParamEntry(self, event):
00672         """!Parameter value changed"""
00673         id  = event.GetId()
00674         val = event.GetString()
00675         
00676         if id not in self.pparam:
00677             event.Skip()
00678             return
00679 
00680         param = self.pparam[id]
00681         win = self.FindWindowById(id)
00682         if param['type'] == 'zone':
00683             val = event.GetInt()
00684             if val < 1:
00685                 win.SetValue(1)
00686             elif val > 60:
00687                     win.SetValue(60)
00688         
00689         if param['type'] == 'bool':
00690             param['value'] = event.GetSelection()
00691         else:
00692             param['value'] = val
00693         
00694         event.Skip()
00695         
00696     def OnPageChange(self,event=None):
00697         """!Go to next page"""
00698         if event.GetDirection():
00699             self.p4projparams = ''
00700             for id, param in self.pparam.iteritems():
00701                 if param['type'] == 'bool':
00702                     if param['value'] == False:
00703                         continue
00704                     else:
00705                         self.p4projparams += (' +' + param['proj4'])
00706                 else:
00707                     if param['value'] is None:
00708                         wx.MessageBox(parent = self,
00709                                       message = _('You must enter a value for %s') % param['desc'],
00710                                       caption = _('Error'), style = wx.ICON_ERROR | wx.CENTRE)
00711                         event.Veto()
00712                     else:
00713                         self.p4projparams += (' +' + param['proj4'] + '=' + str(param['value']))
00714 
00715     def OnEnterPage(self,event):
00716         """!Page entered"""
00717         self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
00718         if self.prjParamSizer is None:
00719             # entering page for the first time
00720             self.paramSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
00721                                      label = _(" Enter parameters for %s projection ") % self.projdesc)
00722             paramSBSizer = wx.StaticBoxSizer(self.paramSBox)
00723             
00724             self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
00725             self.panel.SetupScrolling()
00726             
00727             self.prjParamSizer = wx.GridBagSizer(vgap = 0, hgap = 0) 
00728             
00729             self.sizer.Add(item = paramSBSizer, pos = (1, 1),
00730                            flag = wx.EXPAND)
00731             paramSBSizer.Add(item = self.panel, proportion = 1, 
00732                              flag = wx.ALIGN_CENTER | wx.EXPAND)
00733             
00734             paramSBSizer.Fit(self.panel)
00735             self.panel.SetSizer(self.prjParamSizer)
00736                     
00737         if event.GetDirection(): 
00738             self.prjParamSizer.Clear(True)
00739             self.paramSBox.SetLabel(_(" Enter parameters for %s projection ") % self.projdesc)
00740             self.pparam = dict()
00741             row = 0
00742             for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
00743                 # get parameters
00744                 id = wx.NewId()
00745                 param = self.pparam[id] = { 'type' : self.parent.paramdesc[paramgrp[0]][0],
00746                                             'proj4': self.parent.paramdesc[paramgrp[0]][1],
00747                                             'desc' : self.parent.paramdesc[paramgrp[0]][2] }
00748                 
00749                 # default values
00750                 if param['type'] == 'bool':
00751                     param['value'] = 0
00752                 elif param['type'] == 'zone': 
00753                     param['value'] = 30 
00754                     param['desc'] += ' (1-60)'
00755                 else:
00756                     param['value'] = paramgrp[2]
00757                 
00758                 label = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = param['desc'], 
00759                                       style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
00760                 if param['type'] == 'bool':
00761                     win = wx.Choice(parent = self.panel, id = id, size = (100,-1), 
00762                                     choices = [_('No'), _('Yes')])  
00763                     win.SetSelection(param['value'])
00764                     win.Bind(wx.EVT_CHOICE, self.OnParamEntry)
00765                 elif param['type'] == 'zone':
00766                     win = wx.SpinCtrl(parent = self.panel, id = id,
00767                                       size = (100, -1), 
00768                                       style = wx.SP_ARROW_KEYS | wx.SP_WRAP,
00769                                       min = 1, max = 60)
00770                     win.SetValue(param['value'])
00771                     win.Bind(wx.EVT_SPINCTRL, self.OnParamEntry)
00772                     win.Bind(wx.EVT_TEXT, self.OnParamEntry)
00773                 else:
00774                     win = wx.TextCtrl(parent = self.panel, id = id,
00775                                       value = param['value'],
00776                                       size=(100, -1))
00777                     win.Bind(wx.EVT_TEXT, self.OnParamEntry)
00778                     if paramgrp[1] == 'noask':
00779                         win.Enable(False)
00780                     
00781                 self.prjParamSizer.Add(item = label, pos = (row, 1),
00782                                        flag = wx.ALIGN_RIGHT | 
00783                                        wx.ALIGN_CENTER_VERTICAL |
00784                                        wx.RIGHT, border = 5)
00785                 self.prjParamSizer.Add(item = win, pos = (row, 2),
00786                                        flag = wx.ALIGN_LEFT | 
00787                                        wx.ALIGN_CENTER_VERTICAL |
00788                                        wx.LEFT, border = 5)           
00789                 row += 1
00790         
00791         self.panel.SetSize(self.panel.GetBestSize())
00792         self.panel.Layout()
00793         self.Layout()
00794         self.Update()
00795         
00796         if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
00797             wx.FindWindowById(wx.ID_FORWARD).Enable()
00798         
00799         event.Skip()
00800 
00801     def SetVal(self, event):
00802         """!Set value"""
00803         if event.GetId() == self.radio1.GetId():
00804             self.SetNext(self.parent.datumpage)
00805             self.parent.sumpage.SetPrev(self.parent.datumpage)
00806         elif event.GetId() == self.radio2.GetId():
00807             self.SetNext(self.parent.ellipsepage)
00808             self.parent.sumpage.SetPrev(self.parent.ellipsepage)
00809     
00810 class DatumPage(TitledPage):
00811     """!Wizard page for selecting datum (with associated ellipsoid)
00812     and datum transformation parameters (select coordinate system option)
00813     """
00814 
00815     def __init__(self, wizard, parent):
00816         TitledPage.__init__(self, wizard, _("Specify geodetic datum"))
00817 
00818         self.parent = parent
00819         self.datum = ''
00820         self.datumdesc = ''
00821         self.ellipse = ''
00822         self.datumparams = ''
00823         self.proj4params = ''
00824 
00825         # text input
00826         self.tdatum = self.MakeTextCtrl("", size = (200,-1))
00827 
00828         # search box
00829         self.searchb = wx.SearchCtrl(self, size = (200,-1),
00830                                      style = wx.TE_PROCESS_ENTER)
00831 
00832         # create list control for datum/elipsoid list
00833         data = []
00834         for key in self.parent.datums.keys():
00835             data.append([key, self.parent.datums[key][0], self.parent.datums[key][1]])
00836         self.datumlist = ItemList(self,
00837                                   data = data,
00838                                   columns = [_('Code'), _('Ellipsoid'), _('Description')])
00839         self.datumlist.resizeLastColumn(10) 
00840         
00841         # layout
00842         self.sizer.AddGrowableCol(4)
00843         self.sizer.Add(item = self.MakeLabel(_("Datum code:")),
00844                        flag = wx.ALIGN_LEFT |
00845                        wx.ALIGN_CENTER_VERTICAL |
00846                        wx.ALL, border = 5, pos = (1, 1))
00847         self.sizer.Add(item = self.tdatum,
00848                        flag = wx.ALIGN_LEFT |
00849                        wx.ALIGN_CENTER_VERTICAL |
00850                        wx.ALL, border = 5, pos = (1, 2))
00851 
00852         self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
00853                        flag = wx.ALIGN_LEFT |
00854                        wx.ALIGN_CENTER_VERTICAL |
00855                        wx.ALL, border = 5, pos = (2, 1))
00856         self.sizer.Add(item = self.searchb,
00857                        flag = wx.ALIGN_LEFT |
00858                        wx.ALIGN_CENTER_VERTICAL |
00859                        wx.ALL, border = 5, pos = (2, 2))
00860 
00861         self.sizer.AddGrowableRow(3)
00862         self.sizer.Add(item = self.datumlist,
00863                        flag = wx.EXPAND |
00864                        wx.ALIGN_LEFT |
00865                        wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
00866 
00867         # events
00868         self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected)
00869         self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDSearch)
00870         self.tdatum.Bind(wx.EVT_TEXT, self.OnDText)
00871         self.tdatum.Bind(wx.EVT_TEXT_ENTER, self.OnDText)
00872         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
00873         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
00874 
00875         # do page layout
00876         # self.DoLayout()
00877 
00878     def OnPageChanging(self, event):
00879         self.proj4params = ''
00880         proj = self.parent.projpage.p4proj
00881                 
00882         if event.GetDirection():
00883             if self.datum not in self.parent.datums:
00884                 event.Veto()
00885             else:
00886                 # check for datum tranforms            
00887 #                proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
00888                 ret = RunCommand('g.proj',
00889                                  read = True,
00890                                  proj4 = '%s +datum=%s' % (proj, self.datum), 
00891                                  datumtrans = '-1')
00892                 if ret != '':
00893                     dtrans = ''
00894                     # open a dialog to select datum transform number
00895                     dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
00896                     
00897                     if dlg.ShowModal() == wx.ID_OK:
00898                         dtrans = dlg.GetTransform()
00899                         if dtrans == '':
00900                             dlg.Destroy()
00901                             event.Veto()
00902                             return 'Datum transform is required.'
00903                     else:
00904                         dlg.Destroy()
00905                         event.Veto()
00906                         return 'Datum transform is required.'
00907                     
00908                     self.parent.datumtrans = dtrans
00909                 
00910             self.GetNext().SetPrev(self)
00911             self.parent.ellipsepage.ellipse = self.ellipse
00912             self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
00913 
00914     def OnEnterPage(self,event):
00915         self.parent.datumtrans = None
00916         if event.GetDirection():
00917             if len(self.datum) == 0:
00918                 # disable 'next' button by default when entering from previous page
00919                 wx.FindWindowById(wx.ID_FORWARD).Enable(False)
00920             else:
00921                 wx.FindWindowById(wx.ID_FORWARD).Enable(True)
00922 
00923         event.Skip()
00924 
00925     def OnDText(self, event):
00926         """!Datum code changed"""
00927         self.datum = event.GetString()
00928 
00929         nextButton = wx.FindWindowById(wx.ID_FORWARD)
00930         if len(self.datum) == 0 or self.datum not in self.parent.datums:
00931             nextButton.Enable(False)
00932         else:
00933             self.ellipse = self.parent.datums[self.datum][0]
00934             self.datumdesc = self.parent.datums[self.datum][1]
00935             self.datumparams = self.parent.datums[self.datum][2]
00936             try:
00937                 self.datumparams.remove('dx=0.0')
00938             except:
00939                 pass
00940             try:
00941                 self.datumparams.remove('dy=0.0')
00942             except:
00943                 pass
00944             try:
00945                 self.datumparams.remove('dz=0.0')
00946             except:
00947                 pass
00948             
00949             nextButton.Enable(True)
00950             
00951         self.Update()    
00952         event.Skip()
00953 
00954     def OnDSearch(self, event):
00955         """!Search geodetic datum by desc"""
00956         str =  self.searchb.GetValue()
00957         try:
00958             self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search(index = [0,1,2], pattern = str)
00959         except:
00960             self.datum = self.datumdesc = self.ellipsoid = ''
00961 
00962         event.Skip()
00963 
00964     def OnDatumSelected(self, event):
00965         """!Datum selected"""
00966         index = event.m_itemIndex
00967         item = event.GetItem()
00968 
00969         self.datum = self.datumlist.GetItem(index, 0).GetText()
00970         self.tdatum.SetValue(self.datum)
00971         
00972         event.Skip()
00973 
00974 class EllipsePage(TitledPage):
00975     """!Wizard page for selecting ellipsoid (select coordinate system option)"""
00976 
00977     def __init__(self, wizard, parent):
00978         TitledPage.__init__(self, wizard, _("Specify ellipsoid"))
00979 
00980         self.parent = parent
00981         
00982         self.ellipse = ''
00983         self.ellipsedesc = ''
00984         self.ellipseparams = ''
00985         self.proj4params = ''
00986 
00987         # text input
00988         self.tellipse = self.MakeTextCtrl("", size = (200,-1))
00989 
00990         # search box
00991         self.searchb = wx.SearchCtrl(self, size = (200,-1),
00992                                      style = wx.TE_PROCESS_ENTER)
00993 
00994         # create list control for ellipse list
00995         data = []
00996         # extract code, desc
00997         for key in self.parent.ellipsoids.keys():
00998             data.append([key, self.parent.ellipsoids[key][0]])
00999 
01000         self.ellipselist = ItemList(self, data = data,
01001                                     columns = [_('Code'), _('Description')])
01002         self.ellipselist.resizeLastColumn(30)                             
01003 
01004         # layout
01005         self.sizer.AddGrowableCol(4)
01006         self.sizer.Add(item = self.MakeLabel(_("Ellipsoid code:")),
01007                        flag = wx.ALIGN_RIGHT |
01008                        wx.ALIGN_CENTER_VERTICAL |
01009                        wx.ALL, border = 5, pos = (1, 1))
01010         self.sizer.Add(item = self.tellipse,
01011                        flag = wx.ALIGN_LEFT |
01012                        wx.ALIGN_CENTER_VERTICAL |
01013                        wx.ALL, border = 5, pos = (1, 2))
01014         self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
01015                        flag = wx.ALIGN_RIGHT |
01016                        wx.ALIGN_CENTER_VERTICAL |
01017                        wx.ALL, border = 5, pos = (2, 1))
01018         self.sizer.Add(item = self.searchb,
01019                        flag = wx.ALIGN_LEFT |
01020                        wx.ALIGN_CENTER_VERTICAL |
01021                        wx.ALL, border = 5, pos = (2, 2))
01022 
01023         self.sizer.AddGrowableRow(3)
01024         self.sizer.Add(item = self.ellipselist,
01025                        flag = wx.EXPAND |
01026                        wx.ALIGN_LEFT |
01027                        wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
01028 
01029         # events
01030         self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED,    self.OnItemSelected)
01031         self.tellipse.Bind(wx.EVT_TEXT, self.OnText)
01032         self.tellipse.Bind(wx.EVT_TEXT_ENTER, self.OnText)
01033         self.searchb.Bind(wx.EVT_TEXT_ENTER,    self.OnSearch)
01034         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01035         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01036 
01037     def OnEnterPage(self,event):
01038         if len(self.ellipse) == 0:
01039             # disable 'next' button by default
01040             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01041         else:
01042             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01043 
01044         event.Skip()
01045 
01046     def OnPageChanging(self, event):
01047         if event.GetDirection() and self.ellipse not in self.parent.ellipsoids:
01048             event.Veto()
01049 
01050         self.proj4params = ''
01051         self.GetNext().SetPrev(self)
01052         self.parent.datumpage.datumparams = ''
01053         # self.GetNext().SetPrev(self) (???)
01054 
01055     def OnText(self, event):
01056         """!Ellipspoid code changed"""
01057         self.ellipse = event.GetString()
01058         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01059         if len(self.ellipse) == 0 or self.ellipse not in self.parent.ellipsoids:
01060             nextButton.Enable(False)
01061             self.ellipsedesc = ''
01062             self.ellipseparams = ''
01063             self.proj4params = ''
01064         elif self.ellipse in self.parent.ellipsoids:
01065             self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0]
01066             self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
01067             nextButton.Enable(True)
01068 
01069     def OnSearch(self, event):
01070         """!Search ellipsoid by desc"""
01071         try:
01072             self.ellipse, self.ellipsedesc = \
01073                 self.ellipselist.Search(index=[0,1], pattern=event.GetString())
01074             self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
01075         except:
01076             self.ellipse = self.ellipsedesc = self.ellipseparams = ''
01077 
01078         event.Skip()
01079 
01080     def OnItemSelected(self,event):
01081         """!Ellipsoid selected"""
01082         index = event.m_itemIndex
01083         item = event.GetItem()
01084 
01085         self.ellipse = self.ellipselist.GetItem(index, 0).GetText()
01086         self.tellipse.SetValue(self.ellipse)
01087         
01088         event.Skip()
01089 
01090 class GeoreferencedFilePage(TitledPage):
01091     """!Wizard page for selecting georeferenced file to use
01092     for setting coordinate system parameters"""
01093 
01094     def __init__(self, wizard, parent):
01095         TitledPage.__init__(self, wizard, _("Select georeferenced file"))
01096 
01097         self.georeffile = ''
01098 
01099         # create controls
01100         self.lfile= self.MakeLabel(_("Georeferenced file:"))
01101         self.tfile = self.MakeTextCtrl(size = (300,-1))
01102         self.bbrowse = self.MakeButton(_("Browse"))
01103 
01104         # do layout
01105         self.sizer.AddGrowableCol(3)
01106         self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
01107                        wx.ALIGN_CENTRE_VERTICAL |
01108                        wx.ALL, border = 5, pos = (1, 1))
01109         self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
01110                        wx.ALIGN_CENTRE_VERTICAL |
01111                        wx.ALL, border = 5, pos = (1, 2))
01112         self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
01113                        wx.ALL, border = 5, pos = (1, 3))
01114 
01115         self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
01116         self.tfile.Bind(wx.EVT_TEXT, self.OnText)
01117         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01118         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01119 
01120         # do page layout
01121         # self.DoLayout()
01122 
01123     def OnEnterPage(self, event):
01124         if len(self.georeffile) == 0:
01125             # disable 'next' button by default
01126             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01127         else:
01128             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01129 
01130         event.Skip()
01131 
01132     def OnPageChanging(self, event):
01133         if event.GetDirection() and not os.path.isfile(self.georeffile):
01134             event.Veto()
01135         self.GetNext().SetPrev(self)
01136 
01137         event.Skip()
01138 
01139     def OnText(self, event):
01140         """!File changed"""
01141         self.georeffile = event.GetString()
01142         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01143         if len(self.georeffile) > 0 and os.path.isfile(self.georeffile):
01144             if not nextButton.IsEnabled():
01145                 nextButton.Enable(True)
01146         else:
01147             if nextButton.IsEnabled():
01148                 nextButton.Enable(False)
01149 
01150         event.Skip()
01151 
01152     def OnBrowse(self, event):
01153         """!Choose file"""
01154         dlg = wx.FileDialog(self,
01155                             _("Select georeferenced file"),
01156                             os.getcwd(), "", "*.*", wx.OPEN)
01157         if dlg.ShowModal() == wx.ID_OK:
01158             path = dlg.GetPath()
01159             self.tfile.SetValue(path)
01160         dlg.Destroy()
01161 
01162         event.Skip()
01163 
01164 class WKTPage(TitledPage):
01165     """!Wizard page for selecting WKT file to use
01166     for setting coordinate system parameters"""
01167 
01168     def __init__(self, wizard, parent):
01169         TitledPage.__init__(self, wizard, _("Select WKT file"))
01170 
01171         self.wktfile = ''
01172 
01173         # create controls
01174         self.lfile= self.MakeLabel(_("WKT file:"))
01175         self.tfile = self.MakeTextCtrl(size = (300,-1))
01176         self.bbrowse = self.MakeButton(_("Browse"))
01177 
01178         # do layout
01179         self.sizer.AddGrowableCol(3)
01180         self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
01181                        wx.ALIGN_CENTRE_VERTICAL |
01182                        wx.ALL, border = 5, pos = (1, 1))
01183         self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
01184                        wx.ALIGN_CENTRE_VERTICAL |
01185                        wx.ALL, border = 5, pos = (1, 2))
01186         self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
01187                        wx.ALL, border = 5, pos = (1, 3))
01188 
01189         self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
01190         self.tfile.Bind(wx.EVT_TEXT, self.OnText)
01191         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01192         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01193 
01194     def OnEnterPage(self, event):
01195         if len(self.wktfile) == 0:
01196             # disable 'next' button by default
01197             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01198         else:
01199             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01200 
01201         event.Skip()
01202 
01203     def OnPageChanging(self, event):
01204         if event.GetDirection() and not os.path.isfile(self.wktfile):
01205             event.Veto()
01206         self.GetNext().SetPrev(self)
01207 
01208         event.Skip()
01209 
01210     def OnText(self, event):
01211         """!File changed"""
01212         self.wktfile = event.GetString()
01213         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01214         if len(self.wktfile) > 0 and os.path.isfile(self.wktfile):
01215             if not nextButton.IsEnabled():
01216                 nextButton.Enable(True)
01217         else:
01218             if nextButton.IsEnabled():
01219                 nextButton.Enable(False)
01220 
01221         event.Skip()
01222 
01223     def OnBrowse(self, event):
01224         """!Choose file"""
01225         dlg = wx.FileDialog(self,
01226                             _("Select WKT file"),
01227                             os.getcwd(), "", "*.*", wx.OPEN)
01228         if dlg.ShowModal() == wx.ID_OK:
01229             path = dlg.GetPath()
01230             self.tfile.SetValue(path)
01231         dlg.Destroy()
01232 
01233         event.Skip()
01234 
01235 class EPSGPage(TitledPage):
01236     """!Wizard page for selecting EPSG code for
01237     setting coordinate system parameters"""
01238 
01239     def __init__(self, wizard, parent):
01240         TitledPage.__init__(self, wizard, _("Choose EPSG Code"))
01241         self.parent = parent
01242         self.epsgCodeDict = {}
01243         self.epsgcode = None
01244         self.epsgdesc = ''
01245         self.epsgparams = ''
01246 
01247         # labels
01248         self.lfile = self.MakeLabel(_("Path to the EPSG-codes file:"),
01249                                     style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
01250         self.lcode = self.MakeLabel(_("EPSG code:"),
01251                                     style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
01252         # text input
01253         epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
01254         self.tfile = self.MakeTextCtrl(text = epsgdir, size = (200,-1),
01255                                        style = wx.TE_PROCESS_ENTER)
01256         self.tcode = self.MakeTextCtrl(size = (200,-1))
01257 
01258         # buttons
01259         self.bbrowse = self.MakeButton(_("Browse"))
01260         
01261         # search box
01262         self.searchb = wx.SearchCtrl(self, size = (200,-1),
01263                                      style = wx.TE_PROCESS_ENTER)
01264 
01265         self.epsglist = ItemList(self, data = None,
01266                                  columns = [_('Code'), _('Description'), _('Parameters')])
01267 
01268         # layout
01269         self.sizer.AddGrowableCol(3)
01270         self.sizer.Add(item = self.lfile,
01271                        flag = wx.ALIGN_LEFT |
01272                        wx.ALIGN_CENTER_VERTICAL |
01273                        wx.ALL, border = 5, pos = (1, 1), span = (1, 2))
01274         self.sizer.Add(item = self.tfile,
01275                        flag = wx.ALIGN_LEFT |
01276                        wx.ALIGN_CENTER_VERTICAL |
01277                        wx.ALL, border = 5, pos = (1, 3))
01278         self.sizer.Add(item = self.bbrowse,
01279                        flag = wx.ALIGN_LEFT |
01280                        wx.ALIGN_CENTER_VERTICAL |
01281                        wx.ALL, border = 5, pos = (1, 4))
01282         self.sizer.Add(item = self.lcode,
01283                        flag = wx.ALIGN_LEFT |
01284                        wx.ALIGN_CENTER_VERTICAL |
01285                        wx.ALL, border = 5, pos = (2, 1), span = (1, 2))
01286         self.sizer.Add(item = self.tcode,
01287                        flag = wx.ALIGN_LEFT |
01288                        wx.ALIGN_CENTER_VERTICAL |
01289                        wx.ALL, border = 5, pos = (2, 3))
01290         self.sizer.Add(item = self.searchb,
01291                        flag = wx.ALIGN_LEFT |
01292                        wx.ALIGN_CENTER_VERTICAL |
01293                        wx.ALL, border = 5, pos = (3, 3))
01294         
01295         self.sizer.AddGrowableRow(4)
01296         self.sizer.Add(item = self.epsglist,
01297                        flag = wx.ALIGN_LEFT | wx.EXPAND, pos = (4, 1),
01298                        span = (1, 4))
01299 
01300         # events
01301         self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
01302         self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes)
01303         self.tcode.Bind(wx.EVT_TEXT, self.OnText)
01304         self.tcode.Bind(wx.EVT_TEXT_ENTER, self.OnText)
01305         self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
01306         self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
01307         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01308         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01309 
01310     def OnEnterPage(self, event):
01311         self.parent.datumtrans = None
01312         if event.GetDirection():
01313             if not self.epsgcode:
01314                 # disable 'next' button by default
01315                 wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01316             else:
01317                 wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01318 
01319         # load default epsg database file
01320         self.OnBrowseCodes(None)
01321         
01322         event.Skip()
01323 
01324     def OnPageChanging(self, event):
01325         if event.GetDirection():
01326             if not self.epsgcode:
01327                 event.Veto()
01328                 return
01329             else:              
01330                 # check for datum transforms
01331                 ret = RunCommand('g.proj',
01332                                  read = True,
01333                                  epsg = self.epsgcode,
01334                                  datumtrans = '-1')
01335                 
01336                 if ret != '':
01337                     dtrans = ''
01338                     # open a dialog to select datum transform number
01339                     dlg = SelectTransformDialog(self.parent.parent, transforms = ret)
01340                     
01341                     if dlg.ShowModal() == wx.ID_OK:
01342                         dtrans = dlg.GetTransform()
01343                         if dtrans == '':
01344                             dlg.Destroy()
01345                             event.Veto()
01346                             return 'Datum transform is required.'
01347                     else:
01348                         dlg.Destroy()
01349                         event.Veto()
01350                         return 'Datum transform is required.'
01351                     
01352                     self.parent.datumtrans = dtrans
01353             self.GetNext().SetPrev(self)
01354 
01355     def OnText(self, event):
01356         self.epsgcode = event.GetString()
01357         try:
01358             self.epsgcode = int(self.epsgcode)
01359         except:
01360             self.epsgcode = None
01361             
01362         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01363 
01364         if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys():
01365             self.epsgdesc = self.epsgCodeDict[self.epsgcode][0]
01366             self.epsgparams = self.epsgCodeDict[self.epsgcode][1]
01367             if not nextButton.IsEnabled():
01368                 nextButton.Enable(True)
01369         else:
01370             self.epsgcode = None # not found
01371             if nextButton.IsEnabled():
01372                 nextButton.Enable(False)
01373             self.epsgdesc = self.epsgparams = ''
01374         
01375     def OnSearch(self, event):
01376         value =  self.searchb.GetValue()
01377         
01378         if value == '':
01379             self.epsgcode = None
01380             self.epsgdesc = self.epsgparams = ''
01381             self.tcode.SetValue('')
01382             self.searchb.SetValue('')
01383             self.OnBrowseCodes(None)
01384         else:    
01385             try:
01386                 self.epsgcode, self.epsgdesc, self.epsgparams = \
01387                         self.epsglist.Search(index=[0,1,2], pattern=value)
01388             except (IndexError, ValueError): # -> no item found
01389                 self.epsgcode = None
01390                 self.epsgdesc = self.epsgparams = ''
01391                 self.tcode.SetValue('')
01392                 self.searchb.SetValue('')
01393 
01394         event.Skip()
01395         
01396     def OnBrowse(self, event):
01397         """!Define path for EPSG code file"""
01398         path = os.path.dirname(self.tfile.GetValue())
01399         if not path:
01400             path = os.getcwd()
01401         
01402         dlg = wx.FileDialog(parent = self, message = _("Choose EPSG codes file"),
01403                             defaultDir = path, defaultFile = "", wildcard = "*", style = wx.OPEN)
01404         
01405         if dlg.ShowModal() == wx.ID_OK:
01406             path = dlg.GetPath()
01407             self.tfile.SetValue(path)
01408             self.OnBrowseCodes(None)
01409         
01410         dlg.Destroy()
01411 
01412         event.Skip()
01413 
01414     def OnItemSelected(self, event):
01415         """!EPSG code selected from the list"""
01416         index = event.m_itemIndex
01417         item = event.GetItem()
01418 
01419         self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText())
01420         self.epsgdesc = self.epsglist.GetItem(index, 1).GetText()
01421         self.tcode.SetValue(str(self.epsgcode))
01422 
01423         event.Skip()
01424         
01425     def OnBrowseCodes(self, event, search = None):
01426         """!Browse EPSG codes"""
01427         self.epsgCodeDict = utils.ReadEpsgCodes(self.tfile.GetValue())
01428 
01429         if type(self.epsgCodeDict) != dict:
01430             wx.MessageBox(parent = self,
01431                           message = _("Unable to read EPGS codes: %s") % self.epsgCodeDict,
01432                           caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
01433             self.epsglist.Populate(list(), update = True)
01434             return
01435         
01436         data = list()
01437         for code, val in self.epsgCodeDict.iteritems():
01438             if code is not None:
01439                 data.append((code, val[0], val[1]))
01440         
01441         self.epsglist.Populate(data, update = True)
01442         
01443 class CustomPage(TitledPage):
01444     """!Wizard page for entering custom PROJ.4 string
01445     for setting coordinate system parameters"""
01446 
01447     def __init__(self, wizard, parent):
01448         TitledPage.__init__(self, wizard,
01449                             _("Choose method of specifying georeferencing parameters"))
01450         global coordsys
01451         self.customstring = ''
01452         self.parent = parent
01453 
01454         # widgets
01455         self.text_proj4string = self.MakeTextCtrl(size = (400, 200),
01456                                                   style = wx.TE_MULTILINE)
01457         self.label_proj4string = self.MakeLabel(_("Enter PROJ.4 parameters string:"))
01458 
01459         # layout
01460         self.sizer.AddGrowableCol(2)
01461         self.sizer.Add(self.label_proj4string,
01462                        flag = wx.ALIGN_LEFT | wx.ALL,
01463                        border = 5, pos = (1, 1))
01464         self.sizer.AddGrowableRow(2)
01465         self.sizer.Add(self.text_proj4string,
01466                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 
01467                        border = 5, pos = (2, 1), span = (1, 2))
01468 
01469         self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring)
01470         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01471         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01472 
01473     def OnEnterPage(self, event):
01474         if len(self.customstring) == 0:
01475             # disable 'next' button by default
01476             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01477         else:
01478             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01479 
01480     def OnPageChanging(self, event):
01481         if event.GetDirection():
01482         # check for datum tranforms            
01483             ret, out, err = RunCommand('g.proj',
01484                                        read = True, getErrorMsg = True,
01485                                        proj4 = self.customstring, 
01486                                        datumtrans = '-1')
01487             if ret != 0:
01488                 wx.MessageBox(parent = self,
01489                               message = err,
01490                               caption = _("Error"),
01491                               style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
01492                 event.Veto()
01493                 return
01494             
01495             if out:
01496                 dtrans = ''
01497                 # open a dialog to select datum transform number
01498                 dlg = SelectTransformDialog(self.parent.parent, transforms = out)
01499                 
01500                 if dlg.ShowModal() == wx.ID_OK:
01501                     dtrans = dlg.GetTransform()
01502                     if len(dtrans) == 0:
01503                         dlg.Destroy()
01504                         event.Veto()
01505                         return _('Datum transform is required.')
01506                 else:
01507                     dlg.Destroy()
01508                     event.Veto()
01509                     return _('Datum transform is required.')
01510                 
01511                 self.parent.datumtrans = dtrans
01512         
01513         self.GetNext().SetPrev(self)
01514             
01515     def GetProjstring(self, event):
01516         """!Change proj string"""
01517         # TODO: check PROJ.4 syntax
01518         self.customstring = event.GetString()
01519         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01520         if len(self.customstring) == 0:
01521             if nextButton.IsEnabled():
01522                 nextButton.Enable(False)
01523         else:
01524             if not nextButton.IsEnabled():
01525                 nextButton.Enable()
01526 
01527 class SummaryPage(TitledPage):
01528     """!Shows summary result of choosing coordinate system parameters
01529     prior to creating location"""
01530     def __init__(self, wizard, parent):
01531         TitledPage.__init__(self, wizard, _("Summary"))
01532         self.parent = parent
01533 
01534         self.panelTitle = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
01535         self.panelProj4string = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
01536         self.panelProj = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
01537 
01538         # labels
01539         self.ldatabase    = self.MakeLabel()
01540         self.llocation    = self.MakeLabel()
01541         self.llocTitle    = self.MakeLabel(parent = self.panelTitle)
01542         self.lprojection  = self.MakeLabel(parent = self.panelProj)
01543         self.lproj4string = self.MakeLabel(parent = self.panelProj4string)
01544         
01545         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01546         
01547         # do sub-page layout
01548         self._doLayout()
01549         
01550     def _doLayout(self):
01551         """!Do page layout"""
01552         self.sizer.AddGrowableCol(1)
01553         self.sizer.AddGrowableRow(3, 1)
01554         self.sizer.AddGrowableRow(4, 1)
01555         self.sizer.AddGrowableRow(5, 5)
01556 
01557         titleSizer = wx.BoxSizer(wx.VERTICAL)
01558         titleSizer.Add(item = self.llocTitle, proportion = 1,
01559                        flag = wx.EXPAND | wx.ALL, border = 5)
01560         self.panelTitle.SetSizer(titleSizer)        
01561         
01562         projSizer = wx.BoxSizer(wx.VERTICAL)
01563         projSizer.Add(item = self.lprojection, proportion = 1,
01564                        flag = wx.EXPAND | wx.ALL, border = 5)
01565         self.panelProj.SetSizer(projSizer)        
01566         
01567         proj4stringSizer = wx.BoxSizer(wx.VERTICAL)
01568         proj4stringSizer.Add(item = self.lproj4string, proportion = 1,
01569                        flag = wx.EXPAND | wx.ALL, border = 5)
01570         self.panelProj4string.SetSizer(proj4stringSizer)
01571 
01572         self.panelProj4string.SetupScrolling()
01573         self.panelProj.SetupScrolling(scroll_y = False)
01574         self.panelTitle.SetupScrolling(scroll_y = False)
01575 
01576         self.sizer.Add(item = self.MakeLabel(_("GRASS Database:")),
01577                        flag = wx.ALIGN_LEFT | wx.ALL,
01578                        border = 5, pos = (1, 0))
01579         self.sizer.Add(item = self.ldatabase, 
01580                        flag = wx.ALIGN_LEFT | wx.ALL,
01581                        border = 5, pos = (1, 1))
01582         self.sizer.Add(item = self.MakeLabel(_("Location Name:")),
01583                        flag = wx.ALIGN_LEFT | wx.ALL,
01584                        border = 5, pos = (2, 0))
01585         self.sizer.Add(item = self.llocation,
01586                        flag = wx.ALIGN_LEFT | wx.ALL,
01587                        border = 5, pos = (2, 1))
01588         self.sizer.Add(item = self.MakeLabel(_("Location Title:")),
01589                        flag = wx.ALIGN_LEFT | wx.ALL,
01590                        border = 5, pos = (3, 0))
01591         self.sizer.Add(item = self.panelTitle,
01592                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
01593                        border = 0, pos = (3, 1))
01594         self.sizer.Add(item = self.MakeLabel(_("Projection:")),
01595                        flag = wx.ALIGN_LEFT | wx.ALL,
01596                        border = 5, pos = (4, 0))
01597         self.sizer.Add(item = self.panelProj,
01598                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
01599                        border = 0, pos = (4, 1))
01600         self.sizer.Add(item = self.MakeLabel(_("PROJ.4 definition:")),
01601                        flag = wx.ALIGN_LEFT | wx.ALL,
01602                        border = 5, pos = (5, 0))
01603         self.sizer.Add(item = self.panelProj4string,
01604                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
01605                        border = 0, pos = (5, 1))
01606    
01607     def OnEnterPage(self, event):
01608         """!Insert values into text controls for summary of location
01609         creation options
01610         """
01611         database = self.parent.startpage.grassdatabase
01612         location = self.parent.startpage.location
01613         proj4string = self.parent.CreateProj4String()
01614         epsgcode = self.parent.epsgpage.epsgcode
01615         dtrans = self.parent.datumtrans
01616         
01617         global coordsys
01618         if coordsys in ('proj', 'epsg'):
01619             if coordsys == 'proj':
01620                 ret, projlabel, err = RunCommand('g.proj',
01621                                                  flags = 'jf',
01622                                                  proj4 = proj4string,
01623                                                  datumtrans = dtrans,
01624                                                  location = location,
01625                                                  getErrorMsg = True,
01626                                                  read = True)
01627             elif coordsys == 'epsg':
01628                 ret, projlabel, err = RunCommand('g.proj',
01629                                                  flags = 'jf',
01630                                                  epsg = epsgcode,
01631                                                  datumtrans = dtrans,
01632                                                  location = location,
01633                                                  getErrorMsg = True,
01634                                                  read = True)
01635 
01636             finishButton = wx.FindWindowById(wx.ID_FORWARD)
01637             if ret == 0:
01638                 self.lproj4string.SetLabel(projlabel.replace(' ', os.linesep))
01639                 finishButton.Enable(True)
01640             else:
01641                 GError(err, parent = self)
01642                 self.lproj4string.SetLabel('')
01643                 finishButton.Enable(False)
01644         
01645         projdesc = self.parent.projpage.projdesc
01646         ellipsedesc = self.parent.ellipsepage.ellipsedesc
01647         datumdesc = self.parent.datumpage.datumdesc
01648         self.ldatabase.SetLabel(database)
01649         self.llocation.SetLabel(location)
01650         self.llocTitle.SetLabel(self.parent.startpage.locTitle)
01651         
01652         label = ''
01653         if coordsys == 'epsg':
01654             label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
01655         elif coordsys == 'file':
01656             label = 'matches file %s' % self.parent.filepage.georeffile
01657             self.lproj4string.SetLabel("")
01658         elif coordsys == 'wkt':
01659             label = 'matches file %s' % self.parent.wktpage.wktfile
01660             self.lproj4string.SetLabel("")
01661         elif coordsys == 'proj':
01662             label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
01663         elif coordsys == 'xy':
01664             label = ('XY coordinate system (not projected).')
01665             self.lproj4string.SetLabel("")
01666         elif coordsys == 'custom':
01667             label = _("custom")
01668             self.lproj4string.SetLabel(('%s' % self.parent.custompage.customstring.replace(' ', os.linesep)))
01669         self.lprojection.SetLabel(label)
01670         
01671     def OnFinish(self, event):
01672         dlg = wx.MessageDialog(parent = self.wizard,
01673                                message = _("Do you want to create GRASS location <%s>?") % location,
01674                                caption = _("Create new location?"),
01675                                style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
01676         
01677         if dlg.ShowModal() == wx.ID_NO:
01678             dlg.Destroy()
01679             event.Veto()
01680         else:
01681             dlg.Destroy()
01682             event.Skip()
01683 
01684 class LocationWizard(wx.Object):
01685     """!Start wizard here and finish wizard here
01686     """
01687     def __init__(self, parent, grassdatabase):
01688         self.__cleanUp()
01689         
01690         global coordsys
01691         self.parent = parent
01692         
01693         #
01694         # define wizard image
01695         #
01696         imagePath = os.path.join(globalvar.ETCIMGDIR, "loc_wizard_qgis.png")
01697         wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
01698         wizbmp = wizbmp.ConvertToBitmap()
01699         
01700         #
01701         # get georeferencing information from tables in $GISBASE/etc
01702         #
01703         self.__readData()
01704         
01705         #
01706         # datum transform number and list of datum transforms
01707         #
01708         self.datumtrans = None
01709         self.proj4string = ''
01710         
01711         #
01712         # define wizard pages
01713         #
01714         self.wizard = wiz.Wizard(parent, id = wx.ID_ANY, title = _("Define new GRASS Location"),
01715                                  bitmap = wizbmp, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
01716         self.startpage = DatabasePage(self.wizard, self, grassdatabase)
01717         self.csystemspage = CoordinateSystemPage(self.wizard, self)
01718         self.projpage = ProjectionsPage(self.wizard, self)
01719         self.datumpage = DatumPage(self.wizard, self)
01720         self.paramspage = ProjParamsPage(self.wizard,self)
01721         self.epsgpage = EPSGPage(self.wizard, self)
01722         self.filepage = GeoreferencedFilePage(self.wizard, self)
01723         self.wktpage = WKTPage(self.wizard, self)
01724         self.ellipsepage = EllipsePage(self.wizard, self)
01725         self.custompage = CustomPage(self.wizard, self)
01726         self.sumpage = SummaryPage(self.wizard, self)
01727 
01728         #
01729         # set the initial order of the pages
01730         # (should follow the epsg line)
01731         #
01732         self.startpage.SetNext(self.csystemspage)
01733 
01734         self.csystemspage.SetPrev(self.startpage)
01735         self.csystemspage.SetNext(self.sumpage)
01736 
01737         self.projpage.SetPrev(self.csystemspage)
01738         self.projpage.SetNext(self.paramspage)
01739 
01740         self.paramspage.SetPrev(self.projpage)
01741         self.paramspage.SetNext(self.datumpage)
01742 
01743         self.datumpage.SetPrev(self.paramspage)
01744         self.datumpage.SetNext(self.sumpage)
01745 
01746         self.ellipsepage.SetPrev(self.paramspage)
01747         self.ellipsepage.SetNext(self.sumpage)
01748 
01749         self.epsgpage.SetPrev(self.csystemspage)
01750         self.epsgpage.SetNext(self.sumpage)
01751 
01752         self.filepage.SetPrev(self.csystemspage)
01753         self.filepage.SetNext(self.sumpage)
01754 
01755         self.wktpage.SetPrev(self.csystemspage)
01756         self.wktpage.SetNext(self.sumpage)
01757 
01758         self.custompage.SetPrev(self.csystemspage)
01759         self.custompage.SetNext(self.sumpage)
01760 
01761         self.sumpage.SetPrev(self.csystemspage)
01762         
01763         #
01764         # do pages layout
01765         #
01766         self.startpage.DoLayout()
01767         self.csystemspage.DoLayout()
01768         self.projpage.DoLayout()
01769         self.datumpage.DoLayout()
01770         self.paramspage.DoLayout()
01771         self.epsgpage.DoLayout()
01772         self.filepage.DoLayout()
01773         self.wktpage.DoLayout()
01774         self.ellipsepage.DoLayout()
01775         self.custompage.DoLayout()
01776         self.sumpage.DoLayout()
01777         self.wizard.FitToPage(self.datumpage)
01778         size = self.wizard.GetPageSize()
01779         self.wizard.SetPageSize((size[0], size[1] + 75))
01780         
01781         # new location created?
01782         self.location = None 
01783         success = False
01784         
01785         # location created in different GIS database?
01786         self.altdb = False
01787 
01788         #
01789         # run wizard...
01790         #
01791         if self.wizard.RunWizard(self.startpage):
01792             msg = self.OnWizFinished()
01793             if not msg:
01794                 self.wizard.Destroy()
01795                 self.location = self.startpage.location
01796                 
01797                 if self.altdb == False: 
01798                     dlg = wx.MessageDialog(parent = self.parent,
01799                                            message = _("Do you want to set the default "
01800                                                      "region extents and resolution now?"),
01801                                            caption = _("Location <%s> created") % self.location,
01802                                            style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
01803                     dlg.CenterOnScreen()
01804                     if dlg.ShowModal() == wx.ID_YES:
01805                         dlg.Destroy()
01806                         defineRegion = RegionDef(self.parent, location = self.location)
01807                         defineRegion.CenterOnScreen()
01808                         defineRegion.Show()
01809                     else:
01810                         dlg.Destroy()
01811             else: # -> error
01812                 self.wizard.Destroy()
01813                 GError(parent = self.parent,
01814                        message = "%s" % _("Unable to create new location. "
01815                                           "Location <%(loc)s> not created.\n\n"
01816                                           "Details: %(err)s") % \
01817                            { 'loc' : self.startpage.location,
01818                              'err' : msg })
01819         else: # -> canceled
01820             self.wizard.Destroy()
01821             GMessage(parent = self.parent,
01822                      message = _("Location wizard canceled. "
01823                                  "Location not created."))
01824             
01825         self.__cleanUp()
01826         
01827     def __cleanUp(self):
01828         global coordsys
01829         global north
01830         global south
01831         global east
01832         global west
01833         global resolution
01834         global wizerror
01835         global translist
01836         
01837         coordsys = None
01838         north = None
01839         south = None
01840         east = None
01841         west = None
01842         resolution = None
01843         transformlist = list()
01844 
01845     def __readData(self):
01846         """!Get georeferencing information from tables in $GISBASE/etc"""
01847 
01848         # read projection and parameters
01849         f = open(os.path.join(globalvar.ETCDIR, "proj-parms.table"), "r")
01850         self.projections = {}
01851         self.projdesc = {}
01852         for line in f.readlines():
01853             line = line.strip()
01854             try:
01855                 proj, projdesc, params = line.split(':')
01856                 paramslist = params.split(';')
01857                 plist = []
01858                 for p in paramslist:
01859                     if p == '': continue
01860                     p1, pdefault = p.split(',')
01861                     pterm, pask = p1.split('=')
01862                     p = [pterm.strip(), pask.strip(), pdefault.strip()]
01863                     plist.append(p)
01864                 self.projections[proj.lower().strip()] = (projdesc.strip(), plist)
01865                 self.projdesc[proj.lower().strip()] = projdesc.strip()
01866             except:
01867                 continue
01868         f.close()
01869 
01870         # read datum definitions
01871         f = open(os.path.join(globalvar.ETCDIR, "datum.table"), "r")
01872         self.datums = {}
01873         paramslist = []
01874         for line in f.readlines():
01875             line = line.expandtabs(1)
01876             line = line.strip()
01877             if line == '' or line[0] == "#":
01878                 continue
01879             datum, info = line.split(" ", 1)
01880             info = info.strip()
01881             datumdesc, params = info.split(" ", 1)
01882             datumdesc = datumdesc.strip('"')
01883             paramlist = params.split()
01884             ellipsoid = paramlist.pop(0)
01885             self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist)
01886         f.close()
01887 
01888         # read ellipsiod definitions
01889         f = open(os.path.join(globalvar.ETCDIR, "ellipse.table"), "r")
01890         self.ellipsoids = {}
01891         for line in f.readlines():
01892             line = line.expandtabs(1)
01893             line = line.strip()
01894             if line == '' or line[0] == "#":
01895                 continue
01896             ellipse, rest = line.split(" ", 1)
01897             rest = rest.strip('" ')
01898             desc, params = rest.split('"', 1)
01899             desc = desc.strip('" ')
01900             paramslist = params.split()
01901             self.ellipsoids[ellipse] = (desc, paramslist)
01902         f.close()
01903         
01904         # read projection parameter description and parsing table
01905         f = open(os.path.join(globalvar.ETCDIR, "proj-desc.table"), "r")
01906         self.paramdesc = {}
01907         for line in f.readlines():
01908             line = line.strip()
01909             try:
01910                 pparam, datatype, proj4term, desc = line.split(':')
01911                 self.paramdesc[pparam] = (datatype, proj4term, desc)
01912             except:
01913                 continue
01914         f.close()
01915 
01916     def OnWizFinished(self):
01917         """!Wizard finished, create new location
01918 
01919         @return error message on error
01920         @return None on success
01921         """
01922         database = self.startpage.grassdatabase
01923         location = self.startpage.location
01924         
01925         # location already exists?
01926         if os.path.isdir(os.path.join(database,location)):
01927             GError(parent = self.wizard,
01928                    message = "%s <%s>: %s" % \
01929                        (_("Unable to create new location"),
01930                         os.path.join(database, location),
01931                         _("Location already exists in GRASS Database.")))
01932             return None
01933         
01934         # current GISDbase or a new one?
01935         current_gdb = grass.gisenv()['GISDBASE']
01936         if current_gdb != database:
01937             # change to new GISDbase or create new one
01938             if os.path.isdir(database) != True:
01939                 # create new directory
01940                 os.mkdir(database)
01941             
01942             # change to new GISDbase directory
01943             RunCommand('g.gisenv',
01944                        parent = self.wizard,
01945                        set = 'GISDBASE=%s' % database)
01946             
01947             wx.MessageBox(parent = self.wizard,
01948                           message = _("Location <%(loc)s> will be created "
01949                                     "in GIS data directory <%(dir)s>. "
01950                                     "You will need to change the default GIS "
01951                                     "data directory in the GRASS startup screen.") % \
01952                               { 'loc' : location, 'dir' : database},
01953                           caption = _("New GIS data directory"), 
01954                           style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
01955             
01956             # location created in alternate GISDbase
01957             self.altdb = True
01958         
01959         global coordsys
01960         try:
01961             if coordsys == "xy":
01962                 grass.create_location(dbase = self.startpage.grassdatabase,
01963                                       location = self.startpage.location,
01964                                       desc = self.startpage.locTitle)
01965             elif coordsys == "proj":
01966                 grass.create_location(dbase = self.startpage.grassdatabase,
01967                                       location = self.startpage.location,
01968                                       proj4 = self.CreateProj4String(),
01969                                       datum = self.datumtrans,
01970                                       desc = self.startpage.locTitle)
01971             elif coordsys == 'custom':
01972                 grass.create_location(dbase = self.startpage.grassdatabase,
01973                                       location = self.startpage.location,
01974                                       proj4 = self.custompage.customstring,
01975                                       desc = self.startpage.locTitle)
01976             elif coordsys == "epsg":
01977                 if not self.epsgpage.epsgcode:
01978                     return _('EPSG code missing.')
01979                 
01980                 grass.create_location(dbase = self.startpage.grassdatabase,
01981                                       location = self.startpage.location,
01982                                       epsg = self.epsgpage.epsgcode,
01983                                       datum = self.datumtrans,
01984                                       desc = self.startpage.locTitle)
01985             elif coordsys == "file":
01986                 if not self.filepage.georeffile or \
01987                         not os.path.isfile(self.filepage.georeffile):
01988                     return _("File <%s> not found." % self.filepage.georeffile)
01989                 
01990                 grass.create_location(dbase = self.startpage.grassdatabase,
01991                                       location = self.startpage.location,
01992                                       filename = self.filepage.georeffile,
01993                                       desc = self.startpage.locTitle)
01994             elif coordsys == "wkt":
01995                 if not self.wktpage.wktfile or \
01996                         not os.path.isfile(self.wktpage.wktfile):
01997                     return _("File <%s> not found." % self.wktpage.wktfile)
01998                 
01999                 grass.create_location(dbase = self.startpage.grassdatabase,
02000                                       location = self.startpage.location,
02001                                       wkt = self.wktpage.wktfile,
02002                                       desc = self.startpage.locTitle)
02003         
02004         except grass.ScriptError, e:
02005             return e.value
02006         
02007         return None
02008     
02009     def CreateProj4String(self):
02010         """!Constract PROJ.4 string"""
02011         location = self.startpage.location
02012         proj = self.projpage.p4proj
02013         projdesc = self.projpage.projdesc
02014         proj4params = self.paramspage.p4projparams
02015                 
02016         datum = self.datumpage.datum
02017         if self.datumpage.datumdesc:
02018             datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse
02019         else:
02020             datumdesc = ''
02021         datumparams = self.datumpage.datumparams        
02022         ellipse = self.ellipsepage.ellipse
02023         ellipsedesc = self.ellipsepage.ellipsedesc
02024         ellipseparams = self.ellipsepage.ellipseparams
02025                 
02026         #
02027         # creating PROJ.4 string
02028         #
02029         proj4string = '%s %s' % (proj, proj4params)
02030                             
02031         # set ellipsoid parameters
02032         if ellipse != '':
02033             proj4string = '%s +ellps=%s' % (proj4string, ellipse)
02034         for item in ellipseparams:
02035             if item[:4] == 'f=1/':
02036                 item = ' +rf=' + item[4:]
02037             else:
02038                 item = ' +' + item
02039             proj4string = '%s %s' % (proj4string, item)
02040             
02041         # set datum and transform parameters if relevant
02042         if datum != '':
02043             proj4string = '%s +datum=%s' % (proj4string, datum)
02044         if datumparams:
02045             for item in datumparams:
02046                 proj4string = '%s +%s' % (proj4string,item)
02047 
02048         proj4string = '%s +no_defs' % proj4string
02049         
02050         return proj4string