GRASS Programmer's Manual  6.4.2(2012)
location_wizard.py
Go to the documentation of this file.
00001 """!
00002 @package location_wizard.py
00003 
00004 @brief Location wizard - creates a new GRASS Location. User can choose
00005 from multiple methods.
00006 
00007 Classes:
00008  - BaseClass
00009  - TitledPage
00010  - DatabasePage
00011  - CoordinateSystemPage
00012  - ProjectionsPage
00013  - ItemList
00014  - ProjParamsPage
00015  - DatumPage
00016  - EllipsePage
00017  - GeoreferencedFilePage
00018  - EPSGPage
00019  - CustomPage
00020  - SummaryPage
00021  - RegionDef
00022  - LocationWizard
00023  - SelectTransformDialog
00024 
00025 (C) 2007-2011 by the GRASS Development Team
00026 
00027 This program is free software under the GNU General Public License
00028 (>=v2). Read the file COPYING that comes with GRASS for details.
00029 
00030 @author Michael Barton
00031 @author Jachym Cepicky
00032 @author Martin Landa <landa.martin gmail.com>   
00033 """
00034 import os
00035 import shutil
00036 import string
00037 import sys
00038 import locale
00039 import platform
00040 
00041 import wx
00042 import wx.lib.mixins.listctrl as listmix
00043 import wx.wizard as wiz
00044 import wx.lib.scrolledpanel as scrolled
00045 import time
00046 
00047 import gcmd
00048 import globalvar
00049 import utils
00050 from grass.script import core as grass
00051 try:
00052     import subprocess
00053 except:
00054     CompatPath = os.path.join(globalvar.ETCWXDIR)
00055     sys.path.append(CompatPath)
00056     from compat import subprocess
00057 
00058 global coordsys
00059 global north
00060 global south
00061 global east
00062 global west
00063 global resolution
00064 global wizerror
00065 global translist
00066 
00067 class BaseClass(wx.Object):
00068     """!Base class providing basic methods"""
00069     def __init__(self):
00070         pass
00071 
00072     def MakeLabel(self, text = "", style = wx.ALIGN_LEFT, parent = None):
00073         """!Make aligned label"""
00074         if not parent:
00075             parent = self
00076         return wx.StaticText(parent = parent, id = wx.ID_ANY, label = text,
00077                              style = style)
00078 
00079     def MakeTextCtrl(self, text = '', size = (100,-1), style = 0, parent = None):
00080         """!Generic text control"""
00081         if not parent:
00082             parent = self
00083         return wx.TextCtrl(parent = parent, id = wx.ID_ANY, value = text,
00084                            size = size, style = style)
00085 
00086     def MakeButton(self, text, id = wx.ID_ANY, size = (-1,-1), parent = None):
00087         """!Generic button"""
00088         if not parent:
00089             parent = self
00090         return wx.Button(parent = parent, id = id, label = text,
00091                          size = size)
00092 
00093 class TitledPage(BaseClass, wiz.WizardPageSimple):
00094     """!Class to make wizard pages. Generic methods to make labels,
00095     text entries, and buttons.
00096     """
00097     def __init__(self, parent, title):
00098 
00099         self.page = wiz.WizardPageSimple.__init__(self, parent)
00100 
00101         # page title
00102         self.title = wx.StaticText(parent = self, id = wx.ID_ANY, label = title)
00103         self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
00104 
00105         # main sizers
00106         self.pagesizer = wx.BoxSizer(wx.VERTICAL)
00107         self.sizer = wx.GridBagSizer(vgap = 0, hgap = 0)
00108         
00109     def DoLayout(self):
00110         """!Do page layout"""
00111         self.pagesizer.Add(item = self.title, proportion = 0,
00112                            flag = wx.ALIGN_CENTRE | wx.ALL,
00113                            border = 5)
00114         self.pagesizer.Add(item = wx.StaticLine(self, -1), proportion = 0,
00115                            flag = wx.EXPAND | wx.ALL,
00116                            border = 0)
00117         self.pagesizer.Add(item = self.sizer, proportion = 1,
00118                            flag = wx.EXPAND)
00119         
00120         self.SetAutoLayout(True)
00121         self.SetSizer(self.pagesizer)
00122         self.Layout()
00123 
00124 class DatabasePage(TitledPage):
00125     """!Wizard page for setting GIS data directory and location name"""
00126     def __init__(self, wizard, parent, grassdatabase):
00127         TitledPage.__init__(self, wizard, _("Define GRASS Database and Location Name"))
00128 
00129         self.grassdatabase  = grassdatabase
00130         self.location       = ''
00131         self.locTitle       = ''
00132         
00133         # buttons
00134         self.bbrowse = self.MakeButton(_("Browse"))
00135 
00136         # text controls
00137         self.tgisdbase = self.MakeTextCtrl(grassdatabase, size = (300, -1))
00138         self.tlocation = self.MakeTextCtrl("newLocation", size = (300, -1))
00139         self.tlocTitle = self.MakeTextCtrl(size = (400, -1))
00140         
00141         # layout
00142         self.sizer.AddGrowableCol(3)
00143         self.sizer.Add(item = self.MakeLabel(_("GIS Data Directory:")),
00144                        flag = wx.ALIGN_RIGHT |
00145                        wx.ALIGN_CENTER_VERTICAL |
00146                        wx.ALL, border = 5,
00147                        pos = (1, 1))
00148         self.sizer.Add(item = self.tgisdbase,
00149                        flag = wx.ALIGN_LEFT |
00150                        wx.ALIGN_CENTER_VERTICAL |
00151                        wx.ALL, border = 5,
00152                        pos = (1, 2))
00153         self.sizer.Add(item = self.bbrowse,
00154                        flag = wx.ALIGN_LEFT |
00155                        wx.ALIGN_CENTER_VERTICAL |
00156                        wx.ALL, border = 5,
00157                        pos = (1, 3))
00158         
00159         self.sizer.Add(item = self.MakeLabel("%s:" % _("Project Location")),
00160                        flag = wx.ALIGN_RIGHT |
00161                        wx.ALIGN_CENTER_VERTICAL |
00162                        wx.ALL, border = 5,
00163                        pos = (2, 1))
00164         self.sizer.Add(item = self.tlocation,
00165                        flag = wx.ALIGN_LEFT |
00166                        wx.ALIGN_CENTER_VERTICAL |
00167                        wx.ALL, border = 5,
00168                        pos = (2, 2))
00169 
00170         self.sizer.Add(item = self.MakeLabel("%s:" % _("Location Title")),
00171                        flag = wx.ALIGN_RIGHT |
00172                        wx.ALIGN_TOP | wx.ALIGN_CENTER_VERTICAL |
00173                        wx.ALL, border = 5,
00174                        pos = (3, 1))
00175         self.sizer.Add(item = self.tlocTitle,
00176                        flag = wx.ALIGN_LEFT |
00177                        wx.ALIGN_CENTER_VERTICAL |
00178                        wx.ALL, border = 5,
00179                        pos = (3, 2), span  =  (1, 2))
00180         
00181         # bindings
00182         self.Bind(wx.EVT_BUTTON,                self.OnBrowse, self.bbrowse)
00183         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
00184         self.tgisdbase.Bind(wx.EVT_TEXT,        self.OnChangeName)
00185         self.tlocation.Bind(wx.EVT_TEXT,        self.OnChangeName)
00186         
00187     def OnChangeName(self, event):
00188         """!Name for new location was changed"""
00189         nextButton = wx.FindWindowById(wx.ID_FORWARD)
00190         if len(event.GetString()) > 0:
00191             if not nextButton.IsEnabled():
00192                 nextButton.Enable()
00193         else:
00194             nextButton.Disable()
00195 
00196         event.Skip()
00197 
00198     def OnBrowse(self, event):
00199         """!Choose GRASS data directory"""
00200         dlg = wx.DirDialog(self, _("Choose GRASS data directory:"),
00201                            os.getcwd(), wx.DD_DEFAULT_STYLE)
00202         if dlg.ShowModal() == wx.ID_OK:
00203             self.grassdatabase = dlg.GetPath()
00204             self.tgisdbase.SetValue(self.grassdatabase)
00205             
00206         dlg.Destroy()
00207 
00208     def OnPageChanging(self, event = None):
00209         error = None
00210         if os.path.isdir(os.path.join(self.tgisdbase.GetValue(), self.tlocation.GetValue())):
00211             error = _("Location already exists in GRASS Database.")
00212 
00213         if error:
00214             gcmd.GError(parent = self,
00215                         message="%s <%s>.%s%s" % (_("Unable to create location"),
00216                                                   str(self.tlocation.GetValue()),
00217                                                   os.linesep,
00218                                                   error))
00219             event.Veto()
00220             return
00221 
00222         self.location      = self.tlocation.GetValue()
00223         self.grassdatabase = self.tgisdbase.GetValue()
00224         self.locTitle      = self.tlocTitle.GetValue()
00225         if os.linesep in self.locTitle or \
00226                 len(self.locTitle) > 255:
00227             gcmd.GWarning(parent = self,
00228                           message = _("Title of the location is limited only to one line and "
00229                                       "256 characters. The rest of the text will be ignored."))
00230             self.locTitle = self.locTitle.split(os.linesep)[0][:255]
00231             
00232 class CoordinateSystemPage(TitledPage):
00233     """!Wizard page for choosing method for location creation"""
00234     def __init__(self, wizard, parent):
00235         TitledPage.__init__(self, wizard, _("Choose method for creating a new location"))
00236         
00237         self.parent = parent
00238         global coordsys
00239         
00240         # toggles
00241         self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00242                                      label = _("Select coordinate system parameters from a list"),
00243                                      style  =  wx.RB_GROUP)
00244         self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00245                                      label = _("Select EPSG code of spatial reference system"))
00246         self.radio3 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00247                                      label = _("Read projection and datum terms from a "
00248                                              "georeferenced data file"))
00249         self.radio4 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00250                                      label = _("Read projection and datum terms from a "
00251                                              "WKT or PRJ file"))
00252         self.radio5 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00253                                      label = _("Specify projection and datum terms using custom "
00254                                              "PROJ.4 parameters"))
00255         self.radio6 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00256                                      label = _("Create an arbitrary non-earth coordinate system (XY)"))
00257         
00258         # layout
00259         self.sizer.AddGrowableCol(1)
00260         self.sizer.SetVGap(10)
00261         self.sizer.Add(item = self.radio1,
00262                        flag = wx.ALIGN_LEFT, pos = (1, 1))
00263         self.sizer.Add(item = self.radio2,
00264                        flag = wx.ALIGN_LEFT, pos = (2, 1))
00265         self.sizer.Add(item = self.radio3,
00266                        flag = wx.ALIGN_LEFT, pos = (3, 1))
00267         self.sizer.Add(item = self.radio4,
00268                        flag = wx.ALIGN_LEFT, pos = (4, 1))
00269         self.sizer.Add(item = self.radio5,
00270                        flag = wx.ALIGN_LEFT, pos = (5, 1))
00271         self.sizer.Add(item = self.radio6,
00272                        flag = wx.ALIGN_LEFT, pos = (6, 1))
00273 
00274         # bindings
00275         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
00276         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
00277         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio3.GetId())
00278         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio4.GetId())
00279         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio5.GetId())
00280         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio6.GetId())
00281         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
00282         
00283     def OnEnterPage(self, event):
00284         global coordsys
00285         
00286         if not coordsys:
00287             coordsys = "proj"
00288             self.radio1.SetValue(True)
00289         else:
00290             if coordsys == 'proj':
00291                 self.radio1.SetValue(True)
00292             if coordsys == "epsg":
00293                 self.radio2.SetValue(True)
00294             if coordsys == "file":
00295                 self.radio3.SetValue(True)
00296             if coordsys == "wkt":
00297                 self.radio4.SetValue(True)
00298             if coordsys == "custom":
00299                 self.radio5.SetValue(True)
00300             if coordsys == "xy":
00301                 self.radio6.SetValue(True)
00302         
00303         if event.GetDirection():
00304             if coordsys == 'proj':
00305                 self.SetNext(self.parent.projpage)
00306                 self.parent.sumpage.SetPrev(self.parent.datumpage)
00307             if coordsys == "epsg":
00308                 self.SetNext(self.parent.epsgpage)
00309                 self.parent.sumpage.SetPrev(self.parent.epsgpage)
00310             if coordsys == "file":
00311                 self.SetNext(self.parent.filepage)
00312                 self.parent.sumpage.SetPrev(self.parent.filepage)
00313             if coordsys == "wkt":
00314                 self.SetNext(self.parent.wktpage)
00315                 self.parent.sumpage.SetPrev(self.parent.wktpage)
00316             if coordsys == "custom":
00317                 self.SetNext(self.parent.custompage)
00318                 self.parent.sumpage.SetPrev(self.parent.custompage)
00319             if coordsys == "xy":
00320                 self.SetNext(self.parent.sumpage)
00321                 self.parent.sumpage.SetPrev(self.parent.csystemspage)
00322         
00323         if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
00324             wx.FindWindowById(wx.ID_FORWARD).Enable()
00325     
00326     def SetVal(self, event):
00327         """!Choose method"""
00328         global coordsys
00329         if event.GetId() == self.radio1.GetId():
00330             coordsys = "proj"
00331             self.SetNext(self.parent.projpage)
00332             self.parent.sumpage.SetPrev(self.parent.datumpage)
00333         elif event.GetId() == self.radio2.GetId():
00334             coordsys = "epsg"
00335             self.SetNext(self.parent.epsgpage)
00336             self.parent.sumpage.SetPrev(self.parent.epsgpage)
00337         elif event.GetId() == self.radio3.GetId():
00338             coordsys = "file"
00339             self.SetNext(self.parent.filepage)
00340             self.parent.sumpage.SetPrev(self.parent.filepage)
00341         elif event.GetId() == self.radio4.GetId():
00342             coordsys = "wkt"
00343             self.SetNext(self.parent.wktpage)
00344             self.parent.sumpage.SetPrev(self.parent.wktpage)
00345         elif event.GetId() == self.radio5.GetId():
00346             coordsys = "custom"
00347             self.SetNext(self.parent.custompage)
00348             self.parent.sumpage.SetPrev(self.parent.custompage)
00349         elif event.GetId() == self.radio6.GetId():
00350             coordsys = "xy"
00351             self.SetNext(self.parent.sumpage)
00352             self.parent.sumpage.SetPrev(self.parent.csystemspage)
00353 
00354 class ProjectionsPage(TitledPage):
00355     """!Wizard page for selecting projection (select coordinate system option)"""
00356     def __init__(self, wizard, parent):
00357         TitledPage.__init__(self, wizard, _("Choose projection"))
00358 
00359         self.parent = parent
00360         self.proj = ''
00361         self.projdesc = ''
00362         self.p4proj = ''
00363 
00364         # text input
00365         self.tproj = self.MakeTextCtrl("", size = (200,-1))
00366         
00367         # search box
00368         self.searchb = wx.SearchCtrl(self, size = (200,-1),
00369                                      style = wx.TE_PROCESS_ENTER)
00370 
00371         # projection list
00372         self.projlist = ItemList(self, data = self.parent.projdesc.items(),
00373                                  columns = [_('Code'), _('Description')])
00374         self.projlist.resizeLastColumn(30) 
00375 
00376         # layout
00377         self.sizer.AddGrowableCol(3)
00378         self.sizer.Add(item = self.MakeLabel(_("Projection code:")),
00379                        flag = wx.ALIGN_LEFT |
00380                        wx.ALIGN_CENTER_VERTICAL |
00381                        wx.ALL, border = 5, pos = (1, 1))
00382         self.sizer.Add(item = self.tproj,
00383                        flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
00384                        border = 5, pos = (1, 2))
00385 
00386         self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
00387                        flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
00388                        border = 5, pos = (2, 1))
00389         self.sizer.Add(item = self.searchb,
00390                        flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
00391                        border = 5, pos = (2, 2))
00392         
00393         self.sizer.AddGrowableRow(3)
00394         self.sizer.Add(item = self.projlist,
00395                        flag = wx.EXPAND |
00396                        wx.ALIGN_LEFT |
00397                        wx.ALL, border = 5, pos = (3, 1), span = (1, 3))
00398 
00399         # events
00400         self.tproj.Bind(wx.EVT_TEXT, self.OnText)
00401         self.tproj.Bind(wx.EVT_TEXT_ENTER, self.OnText)
00402         self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
00403         self.projlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
00404         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
00405         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
00406         
00407     def OnPageChanging(self,event):
00408         if event.GetDirection() and self.proj not in self.parent.projections.keys():
00409             event.Veto()
00410 
00411     def OnText(self, event):
00412         """!Projection name changed"""
00413         self.proj = event.GetString().lower()
00414         self.p4proj = ''
00415         nextButton = wx.FindWindowById(wx.ID_FORWARD)
00416         if self.proj not in self.parent.projections.keys() and nextButton.IsEnabled():
00417             nextButton.Enable(False)
00418         
00419         if self.proj in self.parent.projections.keys():
00420             if self.proj == 'stp':
00421                 wx.MessageBox('Currently State Plane projections must be selected using the '
00422                               'text-based setup (g.setproj), or entered by EPSG code or '
00423                               'custom PROJ.4 terms.',
00424                               'Warning', wx.ICON_WARNING)
00425                 self.proj = ''
00426                 self.tproj.SetValue(self.proj)
00427                 nextButton.Enable(False)
00428                 return
00429             elif self.proj.lower() == 'll':
00430                 self.p4proj = '+proj=longlat'
00431             else:
00432                 self.p4proj = '+proj=' + self.proj.lower()
00433             self.projdesc = self.parent.projections[self.proj][0]
00434             nextButton.Enable()
00435 
00436     def OnEnterPage(self, event):
00437         if len(self.proj) == 0:
00438             # disable 'next' button by default
00439             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
00440         else:
00441             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
00442 
00443         event.Skip()
00444     
00445     def OnSearch(self, event):
00446         """!Search projection by desc"""
00447         str = event.GetString()
00448         try:
00449             self.proj, self.projdesc = self.projlist.Search(index = [0,1], pattern = event.GetString())
00450         except:
00451             self.proj = self.projdesc = ''
00452             
00453         event.Skip()
00454 
00455     def OnItemSelected(self, event):
00456         """!Projection selected"""
00457         index = event.m_itemIndex
00458 
00459         # set values
00460         self.proj = self.projlist.GetItem(index, 0).GetText().lower()
00461         self.tproj.SetValue(self.proj)
00462         
00463         event.Skip()
00464 
00465 class ItemList(wx.ListCtrl,
00466                listmix.ListCtrlAutoWidthMixin,
00467                listmix.ColumnSorterMixin):
00468     """!Generic list (for projections, ellipsoids, etc.)"""
00469 
00470     def __init__(self, parent, columns, data = None):
00471         wx.ListCtrl.__init__(self, parent = parent, id = wx.ID_ANY,
00472                              style = wx.LC_REPORT |
00473                              wx.LC_VIRTUAL | 
00474                              wx.LC_HRULES |
00475                              wx.LC_VRULES |
00476                              wx.LC_SINGLE_SEL |
00477                              wx.LC_SORT_ASCENDING, size = (550, 125))
00478 
00479         # original data or None
00480         self.sourceData = data
00481         
00482         #
00483         # insert columns
00484         #
00485         i = 0
00486         for column in columns:
00487             self.InsertColumn(i, column)
00488             i += 1
00489 
00490         if self.sourceData:
00491             self.Populate()
00492         
00493         for i in range(self.GetColumnCount()):
00494             self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
00495             if self.GetColumnWidth(i) < 80:
00496                 self.SetColumnWidth(i, 80)
00497         
00498         #
00499         # listmix
00500         #
00501         listmix.ListCtrlAutoWidthMixin.__init__(self)
00502         listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())
00503             
00504         #
00505         # add some attributes
00506         #
00507         self.attr1 = wx.ListItemAttr()
00508         self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
00509         self.attr2 = wx.ListItemAttr()
00510         self.attr2.SetBackgroundColour("white")
00511         self.il = wx.ImageList(16, 16)
00512         self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,   wx.ART_TOOLBAR,
00513                                                           (16,16)))
00514         self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
00515                                                           (16,16)))
00516         self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
00517 
00518         #
00519         # sort by first column
00520         #
00521         if self.sourceData:
00522             self.SortListItems(col = 0, ascending = True)
00523 
00524         #
00525         # bindings
00526         #
00527         self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick)
00528 
00529     def Populate(self, data = None, update = False):
00530         """!Populate list"""
00531         self.itemDataMap  = {}
00532         self.itemIndexMap = []
00533         
00534         if data is None:
00535             data = self.sourceData
00536         elif update:
00537             self.sourceData = data
00538 
00539         try:
00540             data.sort()
00541             self.DeleteAllItems()
00542             row = 0
00543             for value in data:
00544                 self.itemDataMap[row] = [value[0]]
00545                 for i in range(1, len(value)):
00546                      self.itemDataMap[row].append(value[i])
00547                 self.itemIndexMap.append(row)
00548                 row += 1
00549 
00550             self.SetItemCount(row)
00551             
00552             # set column width
00553             self.SetColumnWidth(0, 80)
00554             self.SetColumnWidth(1, 300)
00555             
00556             self.SendSizeEvent()
00557             
00558         except StandardError, e:
00559             wx.MessageBox(parent = self,
00560                           message = _("Unable to read list: %s") % e,
00561                           caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
00562 
00563     def OnColumnClick(self, event):
00564         """!Sort by column"""
00565         self._col = event.GetColumn()
00566 
00567         # remove duplicated arrow symbol from column header
00568         # FIXME: should be done automatically
00569         info = wx.ListItem()
00570         info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
00571         info.m_image = -1
00572         for column in range(self.GetColumnCount()):
00573             info.m_text = self.GetColumn(column).GetText()
00574             self.SetColumn(column, info)
00575 
00576         event.Skip()
00577 
00578     def GetSortImages(self):
00579         """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
00580         return (self.sm_dn, self.sm_up)
00581 
00582     def OnGetItemText(self, item, col):
00583         """!Get item text"""
00584         index = self.itemIndexMap[item]
00585         s = str(self.itemDataMap[index][col])
00586         return s
00587 
00588     def OnGetItemAttr(self, item):
00589         """!Get item attributes"""
00590         index = self.itemIndexMap[item]
00591         if ( index % 2) == 0:
00592             return self.attr2
00593         else:
00594             return self.attr1
00595 
00596     def SortItems(self, sorter = cmp):
00597         """!Sort items"""
00598         items = list(self.itemDataMap.keys())
00599         items.sort(self.Sorter)
00600         self.itemIndexMap = items
00601 
00602         # redraw the list
00603         self.Refresh()
00604         
00605     def Sorter(self, key1, key2):
00606         colName = self.GetColumn(self._col).GetText()
00607         ascending = self._colSortFlag[self._col]
00608         # convert always string
00609         item1 = self.itemDataMap[key1][self._col]
00610         item2 = self.itemDataMap[key2][self._col]
00611 
00612         if type(item1) == type('') or type(item2) == type(''):
00613             cmpVal = locale.strcoll(str(item1), str(item2))
00614         else:
00615             cmpVal = cmp(item1, item2)
00616 
00617 
00618         # If the items are equal then pick something else to make the sort value unique
00619         if cmpVal == 0:
00620             cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
00621 
00622         if ascending:
00623             return cmpVal
00624         else:
00625             return -cmpVal
00626 
00627     def GetListCtrl(self):
00628         """!Used by listmix.ColumnSorterMixin"""
00629         return self
00630 
00631     def Search (self, index, pattern):
00632         """!Search projection by description
00633         Return first found item or None
00634         """
00635         if pattern == '':
00636             self.Populate(self.sourceData)
00637             return []
00638 
00639         data = []
00640         pattern = pattern.lower()
00641         for i in range(len(self.sourceData)):
00642             for idx in index:
00643                 try:
00644                     value = str(self.sourceData[i][idx]).lower()
00645                     if pattern in value:
00646                         data.append(self.sourceData[i])
00647                         break
00648                 except UnicodeDecodeError:
00649                     # osgeo4w problem (should be fixed)
00650                     pass
00651 
00652         self.Populate(data)
00653         if len(data) > 0:
00654             return data[0]
00655         else:
00656             return []
00657 
00658 class ProjParamsPage(TitledPage):
00659     """!Wizard page for selecting method of setting coordinate system
00660     parameters (select coordinate system option)
00661     """
00662     def __init__(self, wizard, parent):
00663         TitledPage.__init__(self, wizard, _("Choose projection parameters"))
00664         global coordsys
00665         
00666         self.parent = parent
00667         self.panel = None
00668         self.prjParamSizer = None
00669         
00670         self.pparam = dict()
00671         
00672         self.p4projparams = ''
00673         self.projdesc = ''
00674 
00675         self.sizer.AddGrowableCol(1)
00676         self.sizer.AddGrowableRow(1)
00677 
00678         radioSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
00679                                  label = " %s " % _("Select datum or ellipsoid (next page)"))
00680         radioSBSizer = wx.StaticBoxSizer(radioSBox)
00681         self.sizer.Add(item = radioSBSizer, pos = (0, 1),
00682                        flag = wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border = 10)
00683         
00684         self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY, 
00685                                      label = _("Datum with associated ellipsoid"),
00686                                      style  =  wx.RB_GROUP)
00687         self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
00688                                      label = _("Ellipsoid only"))   
00689         
00690         # default button setting
00691         if self.radio1.GetValue() == False and self.radio2.GetValue() == False:
00692             self.radio1.SetValue(True)
00693             self.SetNext(self.parent.datumpage)
00694             #            self.parent.sumpage.SetPrev(self.parent.datumpage)  
00695         
00696         radioSBSizer.Add(item = self.radio1,
00697                          flag = wx.ALIGN_LEFT | wx.RIGHT, border = 20)
00698         radioSBSizer.Add(item = self.radio2,
00699                          flag = wx.ALIGN_LEFT)
00700         
00701         # bindings
00702         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
00703         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
00704         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange)
00705         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
00706         
00707     def OnParamEntry(self, event):
00708         """!Parameter value changed"""
00709         id  = event.GetId()
00710         val = event.GetString()
00711         
00712         if id not in self.pparam:
00713             event.Skip()
00714             return
00715 
00716         param = self.pparam[id]
00717         win = self.FindWindowById(id)
00718         if param['type'] == 'zone':
00719             val = event.GetInt()
00720             if val < 1:
00721                 win.SetValue(1)
00722             elif val > 60:
00723                     win.SetValue(60)
00724         
00725         if param['type'] == 'bool':
00726             param['value'] = event.GetSelection()
00727         else:
00728             param['value'] = val
00729         
00730         event.Skip()
00731         
00732     def OnPageChange(self,event=None):
00733         """!Go to next page"""
00734         if event.GetDirection():
00735             self.p4projparams = ''
00736             for id, param in self.pparam.iteritems():
00737                 if param['type'] == 'bool':
00738                     if param['value'] == False:
00739                         continue
00740                     else:
00741                         self.p4projparams += (' +' + param['proj4'])
00742                 else:
00743                     if param['value'] is None:
00744                         wx.MessageBox(parent = self,
00745                                       message = _('You must enter a value for %s') % param['desc'],
00746                                       caption = _('Error'), style = wx.ICON_ERROR | wx.CENTRE)
00747                         event.Veto()
00748                     else:
00749                         self.p4projparams += (' +' + param['proj4'] + '=' + str(param['value']))
00750 
00751     def OnEnterPage(self,event):
00752         """!Page entered"""
00753         self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
00754         if self.prjParamSizer is None:
00755             # entering page for the first time
00756             self.paramSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
00757                                      label = _(" Enter parameters for %s projection ") % self.projdesc)
00758             paramSBSizer = wx.StaticBoxSizer(self.paramSBox)
00759             
00760             self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
00761             self.panel.SetupScrolling()
00762             
00763             self.prjParamSizer = wx.GridBagSizer(vgap = 0, hgap = 0) 
00764             
00765             self.sizer.Add(item = paramSBSizer, pos = (1, 1),
00766                            flag = wx.EXPAND)
00767             paramSBSizer.Add(item = self.panel, proportion = 1, 
00768                              flag = wx.ALIGN_CENTER | wx.EXPAND)
00769             
00770             paramSBSizer.Fit(self.panel)
00771             self.panel.SetSizer(self.prjParamSizer)
00772                     
00773         if event.GetDirection(): 
00774             self.prjParamSizer.Clear(True)
00775             self.paramSBox.SetLabel(_(" Enter parameters for %s projection ") % self.projdesc)
00776             self.pparam = dict()
00777             row = 0
00778             for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
00779                 # get parameters
00780                 id = wx.NewId()
00781                 param = self.pparam[id] = { 'type' : self.parent.paramdesc[paramgrp[0]][0],
00782                                             'proj4': self.parent.paramdesc[paramgrp[0]][1],
00783                                             'desc' : self.parent.paramdesc[paramgrp[0]][2] }
00784                 
00785                 # default values
00786                 if param['type'] == 'bool':
00787                     param['value'] = 0
00788                 elif param['type'] == 'zone': 
00789                     param['value'] = 30 
00790                     param['desc'] += ' (1-60)'
00791                 else:
00792                     param['value'] = paramgrp[2]
00793                 
00794                 label = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = param['desc'], 
00795                                       style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
00796                 if param['type'] == 'bool':
00797                     win = wx.Choice(parent = self.panel, id = id, size = (100,-1), 
00798                                     choices = [_('No'), _('Yes')])  
00799                     win.SetSelection(param['value'])
00800                     win.Bind(wx.EVT_CHOICE, self.OnParamEntry)
00801                 elif param['type'] == 'zone':
00802                     win = wx.SpinCtrl(parent = self.panel, id = id,
00803                                       size = (100, -1), 
00804                                       style = wx.SP_ARROW_KEYS | wx.SP_WRAP,
00805                                       min = 1, max = 60)
00806                     win.SetValue(param['value'])
00807                     win.Bind(wx.EVT_SPINCTRL, self.OnParamEntry)
00808                     win.Bind(wx.EVT_TEXT, self.OnParamEntry)
00809                 else:
00810                     win = wx.TextCtrl(parent = self.panel, id = id,
00811                                       value = param['value'],
00812                                       size=(100, -1))
00813                     win.Bind(wx.EVT_TEXT, self.OnParamEntry)
00814                     if paramgrp[1] == 'noask':
00815                         win.Enable(False)
00816                     
00817                 self.prjParamSizer.Add(item = label, pos = (row, 1),
00818                                        flag = wx.ALIGN_RIGHT | 
00819                                        wx.ALIGN_CENTER_VERTICAL |
00820                                        wx.RIGHT, border = 5)
00821                 self.prjParamSizer.Add(item = win, pos = (row, 2),
00822                                        flag = wx.ALIGN_LEFT | 
00823                                        wx.ALIGN_CENTER_VERTICAL |
00824                                        wx.LEFT, border = 5)           
00825                 row += 1
00826         
00827         self.panel.SetSize(self.panel.GetBestSize())
00828         self.panel.Layout()
00829         self.Layout()
00830         self.Update()
00831         
00832         if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
00833             wx.FindWindowById(wx.ID_FORWARD).Enable()
00834         
00835         event.Skip()
00836 
00837     def SetVal(self, event):
00838         """!Set value"""
00839         if event.GetId() == self.radio1.GetId():
00840             self.SetNext(self.parent.datumpage)
00841             self.parent.sumpage.SetPrev(self.parent.datumpage)
00842         elif event.GetId() == self.radio2.GetId():
00843             self.SetNext(self.parent.ellipsepage)
00844             self.parent.sumpage.SetPrev(self.parent.ellipsepage)
00845     
00846 class DatumPage(TitledPage):
00847     """!Wizard page for selecting datum (with associated ellipsoid)
00848     and datum transformation parameters (select coordinate system option)
00849     """
00850 
00851     def __init__(self, wizard, parent):
00852         TitledPage.__init__(self, wizard, _("Specify geodetic datum"))
00853 
00854         self.parent = parent
00855         self.datum = ''
00856         self.datumdesc = ''
00857         self.ellipse = ''
00858         self.datumparams = ''
00859         self.proj4params = ''
00860 
00861         # text input
00862         self.tdatum = self.MakeTextCtrl("", size = (200,-1))
00863 
00864         # search box
00865         self.searchb = wx.SearchCtrl(self, size = (200,-1),
00866                                      style = wx.TE_PROCESS_ENTER)
00867 
00868         # create list control for datum/elipsoid list
00869         data = []
00870         for key in self.parent.datums.keys():
00871             data.append([key, self.parent.datums[key][0], self.parent.datums[key][1]])
00872         self.datumlist = ItemList(self,
00873                                   data = data,
00874                                   columns = [_('Code'), _('Ellipsoid'), _('Description')])
00875         self.datumlist.resizeLastColumn(10) 
00876         
00877         # layout
00878         self.sizer.AddGrowableCol(4)
00879         self.sizer.Add(item = self.MakeLabel(_("Datum code:")),
00880                        flag = wx.ALIGN_LEFT |
00881                        wx.ALIGN_CENTER_VERTICAL |
00882                        wx.ALL, border = 5, pos = (1, 1))
00883         self.sizer.Add(item = self.tdatum,
00884                        flag = wx.ALIGN_LEFT |
00885                        wx.ALIGN_CENTER_VERTICAL |
00886                        wx.ALL, border = 5, pos = (1, 2))
00887 
00888         self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
00889                        flag = wx.ALIGN_LEFT |
00890                        wx.ALIGN_CENTER_VERTICAL |
00891                        wx.ALL, border = 5, pos = (2, 1))
00892         self.sizer.Add(item = self.searchb,
00893                        flag = wx.ALIGN_LEFT |
00894                        wx.ALIGN_CENTER_VERTICAL |
00895                        wx.ALL, border = 5, pos = (2, 2))
00896 
00897         self.sizer.AddGrowableRow(3)
00898         self.sizer.Add(item = self.datumlist,
00899                        flag = wx.EXPAND |
00900                        wx.ALIGN_LEFT |
00901                        wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
00902 
00903         # events
00904         self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected)
00905         self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDSearch)
00906         self.tdatum.Bind(wx.EVT_TEXT, self.OnDText)
00907         self.tdatum.Bind(wx.EVT_TEXT_ENTER, self.OnDText)
00908         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
00909         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
00910 
00911         # do page layout
00912         # self.DoLayout()
00913 
00914     def OnPageChanging(self, event):
00915         self.proj4params = ''
00916         proj = self.parent.projpage.p4proj
00917                 
00918         if event.GetDirection():
00919             if self.datum not in self.parent.datums:
00920                 event.Veto()
00921             else:
00922                 # check for datum tranforms            
00923 #                proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
00924                 ret = gcmd.RunCommand('g.proj',
00925                                       read = True,
00926                                       proj4 = '%s +datum=%s' % (proj, self.datum), 
00927                                       datumtrans = '-1')
00928                 if ret != '':
00929                     dtrans = ''
00930                     # open a dialog to select datum transform number
00931                     dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
00932                     
00933                     if dlg.ShowModal() == wx.ID_OK:
00934                         dtrans = dlg.GetTransform()
00935                         if dtrans == '':
00936                             dlg.Destroy()
00937                             event.Veto()
00938                             return 'Datum transform is required.'
00939                     else:
00940                         dlg.Destroy()
00941                         event.Veto()
00942                         return 'Datum transform is required.'
00943                     
00944                     self.parent.datumtrans = dtrans
00945                 
00946             self.GetNext().SetPrev(self)
00947             self.parent.ellipsepage.ellipse = self.ellipse
00948             self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
00949 
00950     def OnEnterPage(self,event):
00951         self.parent.datumtrans = None
00952         if event.GetDirection():
00953             if len(self.datum) == 0:
00954                 # disable 'next' button by default when entering from previous page
00955                 wx.FindWindowById(wx.ID_FORWARD).Enable(False)
00956             else:
00957                 wx.FindWindowById(wx.ID_FORWARD).Enable(True)
00958 
00959         event.Skip()
00960 
00961     def OnDText(self, event):
00962         """!Datum code changed"""
00963         self.datum = event.GetString()
00964 
00965         nextButton = wx.FindWindowById(wx.ID_FORWARD)
00966         if len(self.datum) == 0 or self.datum not in self.parent.datums:
00967             nextButton.Enable(False)
00968         else:
00969             self.ellipse = self.parent.datums[self.datum][0]
00970             self.datumdesc = self.parent.datums[self.datum][1]
00971             self.datumparams = self.parent.datums[self.datum][2]
00972             try:
00973                 self.datumparams.remove('dx=0.0')
00974             except:
00975                 pass
00976             try:
00977                 self.datumparams.remove('dy=0.0')
00978             except:
00979                 pass
00980             try:
00981                 self.datumparams.remove('dz=0.0')
00982             except:
00983                 pass
00984             
00985             nextButton.Enable(True)
00986             
00987         self.Update()    
00988         event.Skip()
00989 
00990     def OnDSearch(self, event):
00991         """!Search geodetic datum by desc"""
00992         str =  self.searchb.GetValue()
00993         try:
00994             self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search(index = [0,1,2], pattern = str)
00995         except:
00996             self.datum = self.datumdesc = self.ellipsoid = ''
00997 
00998         event.Skip()
00999 
01000     def OnDatumSelected(self, event):
01001         """!Datum selected"""
01002         index = event.m_itemIndex
01003         item = event.GetItem()
01004 
01005         self.datum = self.datumlist.GetItem(index, 0).GetText()
01006         self.tdatum.SetValue(self.datum)
01007         
01008         event.Skip()
01009 
01010 class EllipsePage(TitledPage):
01011     """!Wizard page for selecting ellipsoid (select coordinate system option)"""
01012 
01013     def __init__(self, wizard, parent):
01014         TitledPage.__init__(self, wizard, _("Specify ellipsoid"))
01015 
01016         self.parent = parent
01017         
01018         self.ellipse = ''
01019         self.ellipsedesc = ''
01020         self.ellipseparams = ''
01021         self.proj4params = ''
01022 
01023         # text input
01024         self.tellipse = self.MakeTextCtrl("", size = (200,-1))
01025 
01026         # search box
01027         self.searchb = wx.SearchCtrl(self, size = (200,-1),
01028                                      style = wx.TE_PROCESS_ENTER)
01029 
01030         # create list control for ellipse list
01031         data = []
01032         # extract code, desc
01033         for key in self.parent.ellipsoids.keys():
01034             data.append([key, self.parent.ellipsoids[key][0]])
01035 
01036         self.ellipselist = ItemList(self, data = data,
01037                                     columns = [_('Code'), _('Description')])
01038         self.ellipselist.resizeLastColumn(30)                             
01039 
01040         # layout
01041         self.sizer.AddGrowableCol(4)
01042         self.sizer.Add(item = self.MakeLabel(_("Ellipsoid code:")),
01043                        flag = wx.ALIGN_RIGHT |
01044                        wx.ALIGN_CENTER_VERTICAL |
01045                        wx.ALL, border = 5, pos = (1, 1))
01046         self.sizer.Add(item = self.tellipse,
01047                        flag = wx.ALIGN_LEFT |
01048                        wx.ALIGN_CENTER_VERTICAL |
01049                        wx.ALL, border = 5, pos = (1, 2))
01050         self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
01051                        flag = wx.ALIGN_RIGHT |
01052                        wx.ALIGN_CENTER_VERTICAL |
01053                        wx.ALL, border = 5, pos = (2, 1))
01054         self.sizer.Add(item = self.searchb,
01055                        flag = wx.ALIGN_LEFT |
01056                        wx.ALIGN_CENTER_VERTICAL |
01057                        wx.ALL, border = 5, pos = (2, 2))
01058 
01059         self.sizer.AddGrowableRow(3)
01060         self.sizer.Add(item = self.ellipselist,
01061                        flag = wx.EXPAND |
01062                        wx.ALIGN_LEFT |
01063                        wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
01064 
01065         # events
01066         self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED,    self.OnItemSelected)
01067         self.tellipse.Bind(wx.EVT_TEXT, self.OnText)
01068         self.tellipse.Bind(wx.EVT_TEXT_ENTER, self.OnText)
01069         self.searchb.Bind(wx.EVT_TEXT_ENTER,    self.OnSearch)
01070         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01071         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01072 
01073     def OnEnterPage(self,event):
01074         if len(self.ellipse) == 0:
01075             # disable 'next' button by default
01076             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01077         else:
01078             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01079 
01080         event.Skip()
01081 
01082     def OnPageChanging(self, event):
01083         if event.GetDirection() and self.ellipse not in self.parent.ellipsoids:
01084             event.Veto()
01085 
01086         self.proj4params = ''
01087         self.GetNext().SetPrev(self)
01088         self.parent.datumpage.datumparams = ''
01089         # self.GetNext().SetPrev(self) (???)
01090 
01091     def OnText(self, event):
01092         """!Ellipspoid code changed"""
01093         self.ellipse = event.GetString()
01094         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01095         if len(self.ellipse) == 0 or self.ellipse not in self.parent.ellipsoids:
01096             nextButton.Enable(False)
01097             self.ellipsedesc = ''
01098             self.ellipseparams = ''
01099             self.proj4params = ''
01100         elif self.ellipse in self.parent.ellipsoids:
01101             self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0]
01102             self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
01103             nextButton.Enable(True)
01104 
01105     def OnSearch(self, event):
01106         """!Search ellipsoid by desc"""
01107         try:
01108             self.ellipse, self.ellipsedesc = \
01109                 self.ellipselist.Search(index=[0,1], pattern=event.GetString())
01110             self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
01111         except:
01112             self.ellipse = self.ellipsedesc = self.ellipseparams = ''
01113 
01114         event.Skip()
01115 
01116     def OnItemSelected(self,event):
01117         """!Ellipsoid selected"""
01118         index = event.m_itemIndex
01119         item = event.GetItem()
01120 
01121         self.ellipse = self.ellipselist.GetItem(index, 0).GetText()
01122         self.tellipse.SetValue(self.ellipse)
01123         
01124         event.Skip()
01125 
01126 class GeoreferencedFilePage(TitledPage):
01127     """!Wizard page for selecting georeferenced file to use
01128     for setting coordinate system parameters"""
01129 
01130     def __init__(self, wizard, parent):
01131         TitledPage.__init__(self, wizard, _("Select georeferenced file"))
01132 
01133         self.georeffile = ''
01134 
01135         # create controls
01136         self.lfile= self.MakeLabel(_("Georeferenced file:"))
01137         self.tfile = self.MakeTextCtrl(size = (300,-1))
01138         self.bbrowse = self.MakeButton(_("Browse"))
01139 
01140         # do layout
01141         self.sizer.AddGrowableCol(3)
01142         self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
01143                        wx.ALIGN_CENTRE_VERTICAL |
01144                        wx.ALL, border = 5, pos = (1, 1))
01145         self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
01146                        wx.ALIGN_CENTRE_VERTICAL |
01147                        wx.ALL, border = 5, pos = (1, 2))
01148         self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
01149                        wx.ALL, border = 5, pos = (1, 3))
01150 
01151         self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
01152         self.tfile.Bind(wx.EVT_TEXT, self.OnText)
01153         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01154         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01155 
01156         # do page layout
01157         # self.DoLayout()
01158 
01159     def OnEnterPage(self, event):
01160         if len(self.georeffile) == 0:
01161             # disable 'next' button by default
01162             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01163         else:
01164             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01165 
01166         event.Skip()
01167 
01168     def OnPageChanging(self, event):
01169         if event.GetDirection() and not os.path.isfile(self.georeffile):
01170             event.Veto()
01171         self.GetNext().SetPrev(self)
01172 
01173         event.Skip()
01174 
01175     def OnText(self, event):
01176         """!File changed"""
01177         self.georeffile = event.GetString()
01178         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01179         if len(self.georeffile) > 0 and os.path.isfile(self.georeffile):
01180             if not nextButton.IsEnabled():
01181                 nextButton.Enable(True)
01182         else:
01183             if nextButton.IsEnabled():
01184                 nextButton.Enable(False)
01185 
01186         event.Skip()
01187 
01188     def OnBrowse(self, event):
01189         """!Choose file"""
01190         dlg = wx.FileDialog(self,
01191                             _("Select georeferenced file"),
01192                             os.getcwd(), "", "*.*", wx.OPEN)
01193         if dlg.ShowModal() == wx.ID_OK:
01194             path = dlg.GetPath()
01195             self.tfile.SetValue(path)
01196         dlg.Destroy()
01197 
01198         event.Skip()
01199 
01200 class WKTPage(TitledPage):
01201     """!Wizard page for selecting WKT file to use
01202     for setting coordinate system parameters"""
01203 
01204     def __init__(self, wizard, parent):
01205         TitledPage.__init__(self, wizard, _("Select WKT file"))
01206 
01207         self.wktfile = ''
01208 
01209         # create controls
01210         self.lfile= self.MakeLabel(_("WKT file:"))
01211         self.tfile = self.MakeTextCtrl(size = (300,-1))
01212         self.bbrowse = self.MakeButton(_("Browse"))
01213 
01214         # do layout
01215         self.sizer.AddGrowableCol(3)
01216         self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
01217                        wx.ALIGN_CENTRE_VERTICAL |
01218                        wx.ALL, border = 5, pos = (1, 1))
01219         self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
01220                        wx.ALIGN_CENTRE_VERTICAL |
01221                        wx.ALL, border = 5, pos = (1, 2))
01222         self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
01223                        wx.ALL, border = 5, pos = (1, 3))
01224 
01225         self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
01226         self.tfile.Bind(wx.EVT_TEXT, self.OnText)
01227         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01228         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01229 
01230     def OnEnterPage(self, event):
01231         if len(self.wktfile) == 0:
01232             # disable 'next' button by default
01233             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01234         else:
01235             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01236 
01237         event.Skip()
01238 
01239     def OnPageChanging(self, event):
01240         if event.GetDirection() and not os.path.isfile(self.wktfile):
01241             event.Veto()
01242         self.GetNext().SetPrev(self)
01243 
01244         event.Skip()
01245 
01246     def OnText(self, event):
01247         """!File changed"""
01248         self.wktfile = event.GetString()
01249         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01250         if len(self.wktfile) > 0 and os.path.isfile(self.wktfile):
01251             if not nextButton.IsEnabled():
01252                 nextButton.Enable(True)
01253         else:
01254             if nextButton.IsEnabled():
01255                 nextButton.Enable(False)
01256 
01257         event.Skip()
01258 
01259     def OnBrowse(self, event):
01260         """!Choose file"""
01261         dlg = wx.FileDialog(self,
01262                             _("Select WKT file"),
01263                             os.getcwd(), "", "*.*", wx.OPEN)
01264         if dlg.ShowModal() == wx.ID_OK:
01265             path = dlg.GetPath()
01266             self.tfile.SetValue(path)
01267         dlg.Destroy()
01268 
01269         event.Skip()
01270 
01271 class EPSGPage(TitledPage):
01272     """!Wizard page for selecting EPSG code for
01273     setting coordinate system parameters"""
01274 
01275     def __init__(self, wizard, parent):
01276         TitledPage.__init__(self, wizard, _("Choose EPSG Code"))
01277         self.parent = parent
01278         self.epsgCodeDict = {}
01279         self.epsgcode = None
01280         self.epsgdesc = ''
01281         self.epsgparams = ''
01282 
01283         # labels
01284         self.lfile = self.MakeLabel(_("Path to the EPSG-codes file:"),
01285                                     style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
01286         self.lcode = self.MakeLabel(_("EPSG code:"),
01287                                     style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
01288         # text input
01289         epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
01290         self.tfile = self.MakeTextCtrl(text = epsgdir, size = (200,-1),
01291                                        style = wx.TE_PROCESS_ENTER)
01292         self.tcode = self.MakeTextCtrl(size = (200,-1))
01293 
01294         # buttons
01295         self.bbrowse = self.MakeButton(_("Browse"))
01296         
01297         # search box
01298         self.searchb = wx.SearchCtrl(self, size = (200,-1),
01299                                      style = wx.TE_PROCESS_ENTER)
01300 
01301         self.epsglist = ItemList(self, data = None,
01302                                  columns = [_('Code'), _('Description'), _('Parameters')])
01303 
01304         # layout
01305         self.sizer.AddGrowableCol(3)
01306         self.sizer.Add(item = self.lfile,
01307                        flag = wx.ALIGN_LEFT |
01308                        wx.ALIGN_CENTER_VERTICAL |
01309                        wx.ALL, border = 5, pos = (1, 1), span = (1, 2))
01310         self.sizer.Add(item = self.tfile,
01311                        flag = wx.ALIGN_LEFT |
01312                        wx.ALIGN_CENTER_VERTICAL |
01313                        wx.ALL, border = 5, pos = (1, 3))
01314         self.sizer.Add(item = self.bbrowse,
01315                        flag = wx.ALIGN_LEFT |
01316                        wx.ALIGN_CENTER_VERTICAL |
01317                        wx.ALL, border = 5, pos = (1, 4))
01318         self.sizer.Add(item = self.lcode,
01319                        flag = wx.ALIGN_LEFT |
01320                        wx.ALIGN_CENTER_VERTICAL |
01321                        wx.ALL, border = 5, pos = (2, 1), span = (1, 2))
01322         self.sizer.Add(item = self.tcode,
01323                        flag = wx.ALIGN_LEFT |
01324                        wx.ALIGN_CENTER_VERTICAL |
01325                        wx.ALL, border = 5, pos = (2, 3))
01326         self.sizer.Add(item = self.searchb,
01327                        flag = wx.ALIGN_LEFT |
01328                        wx.ALIGN_CENTER_VERTICAL |
01329                        wx.ALL, border = 5, pos = (3, 3))
01330         
01331         self.sizer.AddGrowableRow(4)
01332         self.sizer.Add(item = self.epsglist,
01333                        flag = wx.ALIGN_LEFT | wx.EXPAND, pos = (4, 1),
01334                        span = (1, 4))
01335 
01336         # events
01337         self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
01338         self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes)
01339         self.tcode.Bind(wx.EVT_TEXT, self.OnText)
01340         self.tcode.Bind(wx.EVT_TEXT_ENTER, self.OnText)
01341         self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
01342         self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
01343         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01344         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01345 
01346     def OnEnterPage(self, event):
01347         self.parent.datumtrans = None
01348         if event.GetDirection():
01349             if not self.epsgcode:
01350                 # disable 'next' button by default
01351                 wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01352             else:
01353                 wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01354 
01355         # load default epsg database file
01356         self.OnBrowseCodes(None)
01357         
01358         event.Skip()
01359 
01360     def OnPageChanging(self, event):
01361         if event.GetDirection():
01362             if not self.epsgcode:
01363                 event.Veto()
01364                 return
01365             else:              
01366                 # check for datum transforms
01367                 ret = gcmd.RunCommand('g.proj',
01368                                       read = True,
01369                                       epsg = self.epsgcode,
01370                                       datumtrans = '-1')
01371                 
01372                 if ret != '':
01373                     dtrans = ''
01374                     # open a dialog to select datum transform number
01375                     dlg = SelectTransformDialog(self.parent.parent, transforms = ret)
01376                     
01377                     if dlg.ShowModal() == wx.ID_OK:
01378                         dtrans = dlg.GetTransform()
01379                         if dtrans == '':
01380                             dlg.Destroy()
01381                             event.Veto()
01382                             return 'Datum transform is required.'
01383                     else:
01384                         dlg.Destroy()
01385                         event.Veto()
01386                         return 'Datum transform is required.'
01387                     
01388                     self.parent.datumtrans = dtrans
01389             self.GetNext().SetPrev(self)
01390 
01391     def OnText(self, event):
01392         self.epsgcode = event.GetString()
01393         try:
01394             self.epsgcode = int(self.epsgcode)
01395         except:
01396             self.epsgcode = None
01397             
01398         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01399 
01400         if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys():
01401             self.epsgdesc = self.epsgCodeDict[self.epsgcode][0]
01402             self.epsgparams = self.epsgCodeDict[self.epsgcode][1]
01403             if not nextButton.IsEnabled():
01404                 nextButton.Enable(True)
01405         else:
01406             self.epsgcode = None # not found
01407             if nextButton.IsEnabled():
01408                 nextButton.Enable(False)
01409             self.epsgdesc = self.epsgparams = ''
01410         
01411     def OnSearch(self, event):
01412         value =  self.searchb.GetValue()
01413         
01414         if value == '':
01415             self.epsgcode = None
01416             self.epsgdesc = self.epsgparams = ''
01417             self.tcode.SetValue('')
01418             self.searchb.SetValue('')
01419             self.OnBrowseCodes(None)
01420         else:    
01421             try:
01422                 self.epsgcode, self.epsgdesc, self.epsgparams = \
01423                         self.epsglist.Search(index=[0,1,2], pattern=value)
01424             except (IndexError, ValueError): # -> no item found
01425                 self.epsgcode = None
01426                 self.epsgdesc = self.epsgparams = ''
01427                 self.tcode.SetValue('')
01428                 self.searchb.SetValue('')
01429 
01430         event.Skip()
01431         
01432     def OnBrowse(self, event):
01433         """!Define path for EPSG code file"""
01434         path = os.path.dirname(self.tfile.GetValue())
01435         if not path:
01436             path = os.getcwd()
01437         
01438         dlg = wx.FileDialog(parent = self, message = _("Choose EPSG codes file"),
01439                             defaultDir = path, defaultFile = "", wildcard = "*", style = wx.OPEN)
01440         
01441         if dlg.ShowModal() == wx.ID_OK:
01442             path = dlg.GetPath()
01443             self.tfile.SetValue(path)
01444             self.OnBrowseCodes(None)
01445         
01446         dlg.Destroy()
01447 
01448         event.Skip()
01449 
01450     def OnItemSelected(self, event):
01451         """!EPSG code selected from the list"""
01452         index = event.m_itemIndex
01453         item = event.GetItem()
01454 
01455         self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText())
01456         self.epsgdesc = self.epsglist.GetItem(index, 1).GetText()
01457         self.tcode.SetValue(str(self.epsgcode))
01458 
01459         event.Skip()
01460         
01461     def OnBrowseCodes(self, event, search = None):
01462         """!Browse EPSG codes"""
01463         self.epsgCodeDict = utils.ReadEpsgCodes(self.tfile.GetValue())
01464 
01465         if type(self.epsgCodeDict) != dict:
01466             wx.MessageBox(parent = self,
01467                           message = _("Unable to read EPGS codes: %s") % self.epsgCodeDict,
01468                           caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
01469             self.epsglist.Populate(list(), update = True)
01470             return
01471         
01472         data = list()
01473         for code, val in self.epsgCodeDict.iteritems():
01474             if code is not None:
01475                 data.append((code, val[0], val[1]))
01476         
01477         self.epsglist.Populate(data, update = True)
01478         
01479 class CustomPage(TitledPage):
01480     """!Wizard page for entering custom PROJ.4 string
01481     for setting coordinate system parameters"""
01482 
01483     def __init__(self, wizard, parent):
01484         TitledPage.__init__(self, wizard,
01485                             _("Choose method of specifying georeferencing parameters"))
01486         global coordsys
01487         self.customstring = ''
01488         self.parent = parent
01489 
01490         # widgets
01491         self.text_proj4string = self.MakeTextCtrl(size = (400, 200),
01492                                                   style = wx.TE_MULTILINE)
01493         self.label_proj4string = self.MakeLabel(_("Enter PROJ.4 parameters string:"))
01494 
01495         # layout
01496         self.sizer.AddGrowableCol(2)
01497         self.sizer.Add(self.label_proj4string,
01498                        flag = wx.ALIGN_LEFT | wx.ALL,
01499                        border = 5, pos = (1, 1))
01500         self.sizer.AddGrowableRow(2)
01501         self.sizer.Add(self.text_proj4string,
01502                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 
01503                        border = 5, pos = (2, 1), span = (1, 2))
01504 
01505         self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring)
01506         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
01507         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01508 
01509     def OnEnterPage(self, event):
01510         if len(self.customstring) == 0:
01511             # disable 'next' button by default
01512             wx.FindWindowById(wx.ID_FORWARD).Enable(False)
01513         else:
01514             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
01515 
01516     def OnPageChanging(self, event):
01517         if event.GetDirection():
01518         # check for datum tranforms            
01519             ret, out, err = gcmd.RunCommand('g.proj',
01520                                             read = True, getErrorMsg = True,
01521                                             proj4 = self.customstring, 
01522                                             datumtrans = '-1')
01523             if ret != 0:
01524                 wx.MessageBox(parent = self,
01525                               message = err,
01526                               caption = _("Error"),
01527                               style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
01528                 event.Veto()
01529                 return
01530             
01531             if out:
01532                 dtrans = ''
01533                 # open a dialog to select datum transform number
01534                 dlg = SelectTransformDialog(self.parent.parent, transforms = out)
01535                 
01536                 if dlg.ShowModal() == wx.ID_OK:
01537                     dtrans = dlg.GetTransform()
01538                     if len(dtrans) == 0:
01539                         dlg.Destroy()
01540                         event.Veto()
01541                         return _('Datum transform is required.')
01542                 else:
01543                     dlg.Destroy()
01544                     event.Veto()
01545                     return _('Datum transform is required.')
01546                 
01547                 self.parent.datumtrans = dtrans
01548         
01549         self.GetNext().SetPrev(self)
01550             
01551     def GetProjstring(self, event):
01552         """!Change proj string"""
01553         # TODO: check PROJ.4 syntax
01554         self.customstring = event.GetString()
01555         nextButton = wx.FindWindowById(wx.ID_FORWARD)
01556         if len(self.customstring) == 0:
01557             if nextButton.IsEnabled():
01558                 nextButton.Enable(False)
01559         else:
01560             if not nextButton.IsEnabled():
01561                 nextButton.Enable()
01562 
01563 class SummaryPage(TitledPage):
01564     """!Shows summary result of choosing coordinate system parameters
01565     prior to creating location"""
01566     def __init__(self, wizard, parent):
01567         TitledPage.__init__(self, wizard, _("Summary"))
01568         self.parent = parent
01569 
01570         self.panelTitle = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
01571         self.panelProj4string = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
01572         self.panelProj = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
01573 
01574         # labels
01575         self.ldatabase    = self.MakeLabel()
01576         self.llocation    = self.MakeLabel()
01577         self.llocTitle    = self.MakeLabel(parent = self.panelTitle)
01578         self.lprojection  = self.MakeLabel(parent = self.panelProj)
01579         self.lproj4string = self.MakeLabel(parent = self.panelProj4string)
01580         
01581         self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
01582         
01583         # do sub-page layout
01584         self._doLayout()
01585         
01586     def _doLayout(self):
01587         """!Do page layout"""
01588         self.sizer.AddGrowableCol(1)
01589         self.sizer.AddGrowableRow(3, 1)
01590         self.sizer.AddGrowableRow(4, 1)
01591         self.sizer.AddGrowableRow(5, 5)
01592 
01593         titleSizer = wx.BoxSizer(wx.VERTICAL)
01594         titleSizer.Add(item = self.llocTitle, proportion = 1,
01595                        flag = wx.EXPAND | wx.ALL, border = 5)
01596         self.panelTitle.SetSizer(titleSizer)        
01597         
01598         projSizer = wx.BoxSizer(wx.VERTICAL)
01599         projSizer.Add(item = self.lprojection, proportion = 1,
01600                        flag = wx.EXPAND | wx.ALL, border = 5)
01601         self.panelProj.SetSizer(projSizer)        
01602         
01603         proj4stringSizer = wx.BoxSizer(wx.VERTICAL)
01604         proj4stringSizer.Add(item = self.lproj4string, proportion = 1,
01605                        flag = wx.EXPAND | wx.ALL, border = 5)
01606         self.panelProj4string.SetSizer(proj4stringSizer)
01607 
01608         self.panelProj4string.SetupScrolling()
01609         self.panelProj.SetupScrolling(scroll_y = False)
01610         self.panelTitle.SetupScrolling(scroll_y = False)
01611 
01612         self.sizer.Add(item = self.MakeLabel(_("GRASS Database:")),
01613                        flag = wx.ALIGN_LEFT | wx.ALL,
01614                        border = 5, pos = (1, 0))
01615         self.sizer.Add(item = self.ldatabase, 
01616                        flag = wx.ALIGN_LEFT | wx.ALL,
01617                        border = 5, pos = (1, 1))
01618         self.sizer.Add(item = self.MakeLabel(_("Location Name:")),
01619                        flag = wx.ALIGN_LEFT | wx.ALL,
01620                        border = 5, pos = (2, 0))
01621         self.sizer.Add(item = self.llocation,
01622                        flag = wx.ALIGN_LEFT | wx.ALL,
01623                        border = 5, pos = (2, 1))
01624         self.sizer.Add(item = self.MakeLabel(_("Location Title:")),
01625                        flag = wx.ALIGN_LEFT | wx.ALL,
01626                        border = 5, pos = (3, 0))
01627         self.sizer.Add(item = self.panelTitle,
01628                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
01629                        border = 0, pos = (3, 1))
01630         self.sizer.Add(item = self.MakeLabel(_("Projection:")),
01631                        flag = wx.ALIGN_LEFT | wx.ALL,
01632                        border = 5, pos = (4, 0))
01633         self.sizer.Add(item = self.panelProj,
01634                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
01635                        border = 0, pos = (4, 1))
01636         self.sizer.Add(item = self.MakeLabel(_("PROJ.4 definition:")),
01637                        flag = wx.ALIGN_LEFT | wx.ALL,
01638                        border = 5, pos = (5, 0))
01639         self.sizer.Add(item = self.panelProj4string,
01640                        flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
01641                        border = 0, pos = (5, 1))
01642    
01643     def OnEnterPage(self, event):
01644         """!Insert values into text controls for summary of location
01645         creation options
01646         """
01647         database = self.parent.startpage.grassdatabase
01648         location = self.parent.startpage.location
01649         proj4string = self.parent.CreateProj4String()
01650         epsgcode = self.parent.epsgpage.epsgcode
01651         dtrans = self.parent.datumtrans
01652         
01653         global coordsys
01654         if coordsys in ('proj', 'epsg'):
01655             if coordsys == 'proj':
01656                 ret, projlabel, err = gcmd.RunCommand('g.proj',
01657                                                       flags = 'jf',
01658                                                       proj4 = proj4string,
01659                                                       datumtrans = dtrans,
01660                                                       location = location,
01661                                                       getErrorMsg = True,
01662                                                       read = True)
01663             elif coordsys == 'epsg':
01664                 ret, projlabel, err = gcmd.RunCommand('g.proj',
01665                                                       flags = 'jf',
01666                                                       epsg = epsgcode,
01667                                                       datumtrans = dtrans,
01668                                                       location = location,
01669                                                       getErrorMsg = True,
01670                                                       read = True)
01671 
01672             finishButton = wx.FindWindowById(wx.ID_FORWARD)
01673             if ret == 0:
01674                 self.lproj4string.SetLabel(projlabel.replace(' ', os.linesep))
01675                 finishButton.Enable(True)
01676             else:
01677                 gcmd.GError(err, parent = self)
01678                 self.lproj4string.SetLabel('')
01679                 finishButton.Enable(False)
01680         
01681         projdesc = self.parent.projpage.projdesc
01682         ellipsedesc = self.parent.ellipsepage.ellipsedesc
01683         datumdesc = self.parent.datumpage.datumdesc
01684         self.ldatabase.SetLabel(database)
01685         self.llocation.SetLabel(location)
01686         self.llocTitle.SetLabel(self.parent.startpage.locTitle)
01687         
01688         label = ''
01689         if coordsys == 'epsg':
01690             label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
01691         elif coordsys == 'file':
01692             label = 'matches file %s' % self.parent.filepage.georeffile
01693             self.lproj4string.SetLabel("")
01694         elif coordsys == 'wkt':
01695             label = 'matches file %s' % self.parent.wktpage.wktfile
01696             self.lproj4string.SetLabel("")
01697         elif coordsys == 'proj':
01698             label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
01699         elif coordsys == 'xy':
01700             label = ('XY coordinate system (not projected).')
01701             self.lproj4string.SetLabel("")
01702         elif coordsys == 'custom':
01703             label = _("custom")
01704             self.lproj4string.SetLabel(('%s' % self.parent.custompage.customstring.replace(' ', os.linesep)))
01705         self.lprojection.SetLabel(label)
01706         
01707     def OnFinish(self, event):
01708         dlg = wx.MessageDialog(parent = self.wizard,
01709                                message = _("Do you want to create GRASS location <%s>?") % location,
01710                                caption = _("Create new location?"),
01711                                style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
01712         
01713         if dlg.ShowModal() == wx.ID_NO:
01714             dlg.Destroy()
01715             event.Veto()
01716         else:
01717             dlg.Destroy()
01718             event.Skip()
01719 
01720 class LocationWizard(wx.Object):
01721     """!Start wizard here and finish wizard here
01722     """
01723     def __init__(self, parent, grassdatabase):
01724         self.__cleanUp()
01725         
01726         global coordsys
01727         self.parent = parent
01728         
01729         #
01730         # define wizard image
01731         #
01732         imagePath = os.path.join(globalvar.ETCIMGDIR, "loc_wizard_qgis.png")
01733         wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
01734         wizbmp = wizbmp.ConvertToBitmap()
01735         
01736         #
01737         # get georeferencing information from tables in $GISBASE/etc
01738         #
01739         self.__readData()
01740         
01741         #
01742         # datum transform number and list of datum transforms
01743         #
01744         self.datumtrans = None
01745         self.proj4string = ''
01746         
01747         #
01748         # define wizard pages
01749         #
01750         self.wizard = wiz.Wizard(parent, id = wx.ID_ANY, title = _("Define new GRASS Location"),
01751                                  bitmap = wizbmp, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
01752         self.startpage = DatabasePage(self.wizard, self, grassdatabase)
01753         self.csystemspage = CoordinateSystemPage(self.wizard, self)
01754         self.projpage = ProjectionsPage(self.wizard, self)
01755         self.datumpage = DatumPage(self.wizard, self)
01756         self.paramspage = ProjParamsPage(self.wizard,self)
01757         self.epsgpage = EPSGPage(self.wizard, self)
01758         self.filepage = GeoreferencedFilePage(self.wizard, self)
01759         self.wktpage = WKTPage(self.wizard, self)
01760         self.ellipsepage = EllipsePage(self.wizard, self)
01761         self.custompage = CustomPage(self.wizard, self)
01762         self.sumpage = SummaryPage(self.wizard, self)
01763 
01764         #
01765         # set the initial order of the pages
01766         # (should follow the epsg line)
01767         #
01768         self.startpage.SetNext(self.csystemspage)
01769 
01770         self.csystemspage.SetPrev(self.startpage)
01771         self.csystemspage.SetNext(self.sumpage)
01772 
01773         self.projpage.SetPrev(self.csystemspage)
01774         self.projpage.SetNext(self.paramspage)
01775 
01776         self.paramspage.SetPrev(self.projpage)
01777         self.paramspage.SetNext(self.datumpage)
01778 
01779         self.datumpage.SetPrev(self.paramspage)
01780         self.datumpage.SetNext(self.sumpage)
01781 
01782         self.ellipsepage.SetPrev(self.paramspage)
01783         self.ellipsepage.SetNext(self.sumpage)
01784 
01785         self.epsgpage.SetPrev(self.csystemspage)
01786         self.epsgpage.SetNext(self.sumpage)
01787 
01788         self.filepage.SetPrev(self.csystemspage)
01789         self.filepage.SetNext(self.sumpage)
01790 
01791         self.wktpage.SetPrev(self.csystemspage)
01792         self.wktpage.SetNext(self.sumpage)
01793 
01794         self.custompage.SetPrev(self.csystemspage)
01795         self.custompage.SetNext(self.sumpage)
01796 
01797         self.sumpage.SetPrev(self.csystemspage)
01798         
01799         #
01800         # do pages layout
01801         #
01802         self.startpage.DoLayout()
01803         self.csystemspage.DoLayout()
01804         self.projpage.DoLayout()
01805         self.datumpage.DoLayout()
01806         self.paramspage.DoLayout()
01807         self.epsgpage.DoLayout()
01808         self.filepage.DoLayout()
01809         self.wktpage.DoLayout()
01810         self.ellipsepage.DoLayout()
01811         self.custompage.DoLayout()
01812         self.sumpage.DoLayout()
01813         self.wizard.FitToPage(self.datumpage)
01814         size = self.wizard.GetPageSize()
01815         self.wizard.SetPageSize((size[0], size[1] + 75))
01816         
01817         # new location created?
01818         self.location = None 
01819         success = False
01820         
01821         # location created in different GIS database?
01822         self.altdb = False
01823 
01824         #
01825         # run wizard...
01826         #
01827         if self.wizard.RunWizard(self.startpage):
01828             msg = self.OnWizFinished()
01829             if not msg:
01830                 self.wizard.Destroy()
01831                 self.location = self.startpage.location
01832                 
01833                 if self.altdb == False: 
01834                     dlg = wx.MessageDialog(parent = self.parent,
01835                                            message = _("Do you want to set the default "
01836                                                      "region extents and resolution now?"),
01837                                            caption = _("Location <%s> created") % self.location,
01838                                            style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
01839                     dlg.CenterOnScreen()
01840                     if dlg.ShowModal() == wx.ID_YES:
01841                         dlg.Destroy()
01842                         defineRegion = RegionDef(self.parent, location = self.location)
01843                         defineRegion.CenterOnScreen()
01844                         defineRegion.Show()
01845                     else:
01846                         dlg.Destroy()
01847             else: # -> error
01848                 self.wizard.Destroy()
01849                 gcmd.GError(parent = self.parent,
01850                             message = "%s" % _("Unable to create new location. "
01851                                                "Location <%(loc)s> not created.\n\n"
01852                                                "Details: %(err)s") % \
01853                                   { 'loc' : self.startpage.location,
01854                                     'err' : msg })
01855         else: # -> cancelled
01856             self.wizard.Destroy()
01857             gcmd.GMessage(parent = self.parent,
01858                           message = _("Location wizard canceled. "
01859                                     "Location not created."))
01860             
01861         self.__cleanUp()
01862         
01863     def __cleanUp(self):
01864         global coordsys
01865         global north
01866         global south
01867         global east
01868         global west
01869         global resolution
01870         global wizerror
01871         global translist
01872         
01873         coordsys = None
01874         north = None
01875         south = None
01876         east = None
01877         west = None
01878         resolution = None
01879         transformlist = list()
01880 
01881     def __readData(self):
01882         """!Get georeferencing information from tables in $GISBASE/etc"""
01883 
01884         # read projection and parameters
01885         f = open(os.path.join(globalvar.ETCDIR, "proj-parms.table"), "r")
01886         self.projections = {}
01887         self.projdesc = {}
01888         for line in f.readlines():
01889             line = line.strip()
01890             try:
01891                 proj, projdesc, params = line.split(':')
01892                 paramslist = params.split(';')
01893                 plist = []
01894                 for p in paramslist:
01895                     if p == '': continue
01896                     p1, pdefault = p.split(',')
01897                     pterm, pask = p1.split('=')
01898                     p = [pterm.strip(), pask.strip(), pdefault.strip()]
01899                     plist.append(p)
01900                 self.projections[proj.lower().strip()] = (projdesc.strip(), plist)
01901                 self.projdesc[proj.lower().strip()] = projdesc.strip()
01902             except:
01903                 continue
01904         f.close()
01905 
01906         # read datum definitions
01907         f = open(os.path.join(globalvar.ETCDIR, "datum.table"), "r")
01908         self.datums = {}
01909         paramslist = []
01910         for line in f.readlines():
01911             line = line.expandtabs(1)
01912             line = line.strip()
01913             if line == '' or line[0] == "#":
01914                 continue
01915             datum, info = line.split(" ", 1)
01916             info = info.strip()
01917             datumdesc, params = info.split(" ", 1)
01918             datumdesc = datumdesc.strip('"')
01919             paramlist = params.split()
01920             ellipsoid = paramlist.pop(0)
01921             self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist)
01922         f.close()
01923 
01924         # read ellipsiod definitions
01925         f = open(os.path.join(globalvar.ETCDIR, "ellipse.table"), "r")
01926         self.ellipsoids = {}
01927         for line in f.readlines():
01928             line = line.expandtabs(1)
01929             line = line.strip()
01930             if line == '' or line[0] == "#":
01931                 continue
01932             ellipse, rest = line.split(" ", 1)
01933             rest = rest.strip('" ')
01934             desc, params = rest.split('"', 1)
01935             desc = desc.strip('" ')
01936             paramslist = params.split()
01937             self.ellipsoids[ellipse] = (desc, paramslist)
01938         f.close()
01939         
01940         # read projection parameter description and parsing table
01941         f = open(os.path.join(globalvar.ETCDIR, "proj-desc.table"), "r")
01942         self.paramdesc = {}
01943         for line in f.readlines():
01944             line = line.strip()
01945             try:
01946                 pparam, datatype, proj4term, desc = line.split(':')
01947                 self.paramdesc[pparam] = (datatype, proj4term, desc)
01948             except:
01949                 continue
01950         f.close()
01951 
01952     def OnWizFinished(self):
01953         """!Wizard finished, create new location
01954 
01955         @return error message on error
01956         @return None on success
01957         """
01958         database = self.startpage.grassdatabase
01959         location = self.startpage.location
01960         
01961         # location already exists?
01962         if os.path.isdir(os.path.join(database,location)):
01963             gcmd.GError(parent = self.wizard,
01964                         message = "%s <%s>: %s" % \
01965                             (_("Unable to create new location"),
01966                              os.path.join(database, location),
01967                              _("Location already exists in GRASS Database.")))
01968             return None
01969         
01970         # current GISDbase or a new one?
01971         current_gdb = grass.gisenv()['GISDBASE']
01972         if current_gdb != database:
01973             # change to new GISDbase or create new one
01974             if os.path.isdir(database) != True:
01975                 # create new directory
01976                 os.mkdir(database)
01977             
01978             # change to new GISDbase directory
01979             gcmd.RunCommand('g.gisenv',
01980                             parent = self.wizard,
01981                             set = 'GISDBASE=%s' % database)
01982             
01983             wx.MessageBox(parent = self.wizard,
01984                           message = _("Location <%(loc)s> will be created "
01985                                     "in GIS data directory <%(dir)s>. "
01986                                     "You will need to change the default GIS "
01987                                     "data directory in the GRASS startup screen.") % \
01988                               { 'loc' : location, 'dir' : database},
01989                           caption = _("New GIS data directory"), 
01990                           style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
01991             
01992             # location created in alternate GISDbase
01993             self.altdb = True
01994         
01995         global coordsys
01996         try:
01997             if coordsys == "xy":
01998                 grass.create_location(dbase = self.startpage.grassdatabase,
01999                                       location = self.startpage.location,
02000                                       desc = self.startpage.locTitle)
02001             elif coordsys == "proj":
02002                 grass.create_location(dbase = self.startpage.grassdatabase,
02003                                       location = self.startpage.location,
02004                                       proj4 = self.CreateProj4String(),
02005                                       datum = self.datumtrans,
02006                                       desc = self.startpage.locTitle)
02007             elif coordsys == 'custom':
02008                 grass.create_location(dbase = self.startpage.grassdatabase,
02009                                       location = self.startpage.location,
02010                                       proj4 = self.custompage.customstring,
02011                                       desc = self.startpage.locTitle)
02012             elif coordsys == "epsg":
02013                 if not self.epsgpage.epsgcode:
02014                     return _('EPSG code missing.')
02015                 
02016                 grass.create_location(dbase = self.startpage.grassdatabase,
02017                                       location = self.startpage.location,
02018                                       epsg = self.epsgpage.epsgcode,
02019                                       datum = self.datumtrans,
02020                                       desc = self.startpage.locTitle)
02021             elif coordsys == "file":
02022                 if not self.filepage.georeffile or \
02023                         not os.path.isfile(self.filepage.georeffile):
02024                     return _("File <%s> not found." % self.filepage.georeffile)
02025                 
02026                 grass.create_location(dbase = self.startpage.grassdatabase,
02027                                       location = self.startpage.location,
02028                                       filename = self.filepage.georeffile,
02029                                       desc = self.startpage.locTitle)
02030             elif coordsys == "wkt":
02031                 if not self.wktpage.wktfile or \
02032                         not os.path.isfile(self.wktpage.wktfile):
02033                     return _("File <%s> not found." % self.wktpage.wktfile)
02034                 
02035                 grass.create_location(dbase = self.startpage.grassdatabase,
02036                                       location = self.startpage.location,
02037                                       wkt = self.wktpage.wktfile,
02038                                       desc = self.startpage.locTitle)
02039         
02040         except grass.ScriptError, e:
02041             return e.value
02042         
02043         return None
02044     
02045     def CreateProj4String(self):
02046         """!Constract PROJ.4 string"""
02047         location = self.startpage.location
02048         proj = self.projpage.p4proj
02049         projdesc = self.projpage.projdesc
02050         proj4params = self.paramspage.p4projparams
02051                 
02052         datum = self.datumpage.datum
02053         if self.datumpage.datumdesc:
02054             datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse
02055         else:
02056             datumdesc = ''
02057         datumparams = self.datumpage.datumparams        
02058         ellipse = self.ellipsepage.ellipse
02059         ellipsedesc = self.ellipsepage.ellipsedesc
02060         ellipseparams = self.ellipsepage.ellipseparams
02061                 
02062         #
02063         # creating PROJ.4 string
02064         #
02065         proj4string = '%s %s' % (proj, proj4params)
02066                             
02067         # set ellipsoid parameters
02068         if ellipse != '':
02069             proj4string = '%s +ellps=%s' % (proj4string, ellipse)
02070         for item in ellipseparams:
02071             if item[:4] == 'f=1/':
02072                 item = ' +rf=' + item[4:]
02073             else:
02074                 item = ' +' + item
02075             proj4string = '%s %s' % (proj4string, item)
02076             
02077         # set datum and transform parameters if relevant
02078         if datum != '':
02079             proj4string = '%s +datum=%s' % (proj4string, datum)
02080         if datumparams:
02081             for item in datumparams:
02082                 proj4string = '%s +%s' % (proj4string,item)
02083 
02084         proj4string = '%s +no_defs' % proj4string
02085         
02086         return proj4string
02087 
02088 class RegionDef(BaseClass, wx.Frame):
02089     """!Page for setting default region extents and resolution
02090     """
02091     def __init__(self, parent, id = wx.ID_ANY,
02092                  title = _("Set default region extent and resolution"), location = None):
02093         wx.Frame.__init__(self, parent, id, title, size = (650,300))
02094         panel = wx.Panel(self, id = wx.ID_ANY)
02095         
02096         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
02097         
02098         self.parent = parent
02099         self.location = location
02100         
02101         #
02102         # default values
02103         #
02104         # 2D
02105         self.north = 1.0
02106         self.south = 0.0
02107         self.east = 1.0
02108         self.west = 0.0
02109         self.nsres = 1.0
02110         self.ewres = 1.0
02111         # 3D
02112         self.top = 1.0
02113         self.bottom = 0.0
02114         #         self.nsres3 = 1.0
02115         #         self.ewres3 = 1.0
02116         self.tbres  = 1.0
02117         
02118         #
02119         # inputs
02120         #
02121         # 2D
02122         self.tnorth = self.MakeTextCtrl(text = str(self.north), size = (150, -1), parent = panel)
02123         self.tsouth = self.MakeTextCtrl(str(self.south), size = (150, -1), parent = panel)
02124         self.twest = self.MakeTextCtrl(str(self.west), size = (150, -1), parent = panel)
02125         self.teast = self.MakeTextCtrl(str(self.east), size = (150, -1), parent = panel)
02126         self.tnsres = self.MakeTextCtrl(str(self.nsres), size = (150, -1), parent = panel)
02127         self.tewres = self.MakeTextCtrl(str(self.ewres), size = (150, -1), parent = panel)
02128         
02129         #
02130         # labels
02131         #
02132         self.lrows  = self.MakeLabel(parent = panel)
02133         self.lcols  = self.MakeLabel(parent = panel)
02134         self.lcells = self.MakeLabel(parent = panel)
02135         
02136         #
02137         # buttons
02138         #
02139         self.bset = self.MakeButton(text = _("&Set region"), id = wx.ID_OK, parent = panel)
02140         self.bcancel = wx.Button(panel, id = wx.ID_CANCEL)
02141         self.bset.SetDefault()
02142         
02143         #
02144         # image
02145         #
02146         self.img = wx.Image(os.path.join(globalvar.ETCIMGDIR, "qgis_world.png"),
02147                             wx.BITMAP_TYPE_PNG).ConvertToBitmap()
02148         
02149         #
02150         # set current working environment to PERMANENT mapset
02151         # in selected location in order to set default region (WIND)
02152         #
02153         envval = {}
02154         ret = gcmd.RunCommand('g.gisenv',
02155                               read = True)
02156         if ret:
02157             for line in ret.splitlines():
02158                 key, val = line.split('=')
02159                 envval[key] = val
02160             self.currlocation = envval['LOCATION_NAME'].strip("';")
02161             self.currmapset = envval['MAPSET'].strip("';")
02162             if self.currlocation != self.location or self.currmapset != 'PERMANENT':
02163                 gcmd.RunCommand('g.gisenv',
02164                                 set = 'LOCATION_NAME=%s' % self.location)
02165                 gcmd.RunCommand('g.gisenv',
02166                                 set = 'MAPSET=PERMANENT')
02167         else:
02168             dlg = wx.MessageBox(parent = self,
02169                                 message = _('Invalid location selected.'),
02170                                 caption = _("Error"), style = wx.ID_OK | wx.ICON_ERROR)
02171             return
02172         
02173         #
02174         # get current region settings
02175         #
02176         region = {}
02177         ret = gcmd.RunCommand('g.region',
02178                               read = True,
02179                               flags = 'gp3')
02180         if ret:
02181             for line in ret.splitlines():
02182                 key, val = line.split('=')
02183                 region[key] = float(val)
02184         else:
02185             dlg = wx.MessageBox(parent = self,
02186                                 message = _("Invalid region"),
02187                                 caption = _("Error"), style = wx.ID_OK | wx.ICON_ERROR)
02188             dlg.ShowModal()
02189             dlg.Destroy()
02190             return
02191         
02192         #
02193         # update values
02194         # 2D
02195         self.north = float(region['n'])
02196         self.south = float(region['s'])
02197         self.east = float(region['e'])
02198         self.west = float(region['w'])
02199         self.nsres = float(region['nsres'])
02200         self.ewres = float(region['ewres'])
02201         self.rows = int(region['rows'])
02202         self.cols = int(region['cols'])
02203         self.cells = int(region['cells'])
02204         # 3D
02205         self.top = float(region['t'])
02206         self.bottom = float(region['b'])
02207         #         self.nsres3 = float(region['nsres3'])
02208         #         self.ewres3 = float(region['ewres3'])
02209         self.tbres = float(region['tbres'])
02210         self.depth = int(region['depths'])
02211         self.cells3 = int(region['cells3'])
02212         
02213         #
02214         # 3D box collapsable
02215         #
02216         self.infoCollapseLabelExp = _("Click here to show 3D settings")
02217         self.infoCollapseLabelCol = _("Click here to hide 3D settings")
02218         self.settings3D = wx.CollapsiblePane(parent = panel,
02219                                              label = self.infoCollapseLabelExp,
02220                                              style = wx.CP_DEFAULT_STYLE |
02221                                              wx.CP_NO_TLW_RESIZE | wx.EXPAND)
02222         self.MakeSettings3DPaneContent(self.settings3D.GetPane())
02223         self.settings3D.Collapse(False) # FIXME
02224         self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSettings3DPaneChanged, self.settings3D)
02225         
02226         #
02227         # set current region settings
02228         #
02229         self.tnorth.SetValue(str(self.north))
02230         self.tsouth.SetValue(str(self.south))
02231         self.twest.SetValue(str(self.west))
02232         self.teast.SetValue(str(self.east))
02233         self.tnsres.SetValue(str(self.nsres))
02234         self.tewres.SetValue(str(self.ewres))
02235         self.ttop.SetValue(str(self.top))
02236         self.tbottom.SetValue(str(self.bottom))
02237         #         self.tnsres3.SetValue(str(self.nsres3))
02238         #         self.tewres3.SetValue(str(self.ewres3))
02239         self.ttbres.SetValue(str(self.tbres))
02240         self.lrows.SetLabel(_("Rows: %d") % self.rows)
02241         self.lcols.SetLabel(_("Cols: %d") % self.cols)
02242         self.lcells.SetLabel(_("Cells: %d") % self.cells)
02243         
02244         #
02245         # bindings
02246         #
02247         self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset)
02248         self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel)
02249         self.tnorth.Bind(wx.EVT_TEXT,   self.OnValue)
02250         self.tsouth.Bind(wx.EVT_TEXT,   self.OnValue)
02251         self.teast.Bind(wx.EVT_TEXT,    self.OnValue)
02252         self.twest.Bind(wx.EVT_TEXT,    self.OnValue)
02253         self.tnsres.Bind(wx.EVT_TEXT,   self.OnValue)
02254         self.tewres.Bind(wx.EVT_TEXT,   self.OnValue)
02255         self.ttop.Bind(wx.EVT_TEXT,     self.OnValue)
02256         self.tbottom.Bind(wx.EVT_TEXT,  self.OnValue)
02257         #         self.tnsres3.Bind(wx.EVT_TEXT,  self.OnValue)
02258         #         self.tewres3.Bind(wx.EVT_TEXT,  self.OnValue)
02259         self.ttbres.Bind(wx.EVT_TEXT,   self.OnValue)
02260         
02261         self.__DoLayout(panel)
02262         self.SetMinSize(self.GetBestSize())
02263         self.minWindowSize = self.GetMinSize()
02264     
02265     def MakeSettings3DPaneContent(self, pane):
02266         """!Create 3D region settings pane"""
02267         border = wx.BoxSizer(wx.VERTICAL)
02268         gridSizer = wx.GridBagSizer(vgap = 0, hgap = 0)
02269 
02270         # inputs
02271         self.ttop = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.top),
02272                                 size = (150, -1))
02273         self.tbottom = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.bottom),
02274                                 size = (150, -1))
02275         self.ttbres = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.tbres),
02276                                 size = (150, -1))
02277         #         self.tnsres3 = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.nsres3),
02278         #                                    size = (150, -1))
02279         #         self.tewres3  =  wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.ewres3),
02280         #                                    size = (150, -1))
02281 
02282         #labels
02283         self.ldepth = wx.StaticText(parent = pane, label = _("Depth: %d") % self.depth)
02284         self.lcells3  =  wx.StaticText(parent = pane, label = _("3D Cells: %d") % self.cells3)
02285 
02286         # top
02287         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("Top")),
02288                       flag = wx.ALIGN_CENTER |
02289                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
02290                       pos = (0, 1))
02291         gridSizer.Add(item = self.ttop,
02292                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02293                       wx.ALL, border = 5, pos = (1, 1))
02294         # bottom
02295         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("Bottom")),
02296                       flag = wx.ALIGN_CENTER |
02297                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
02298                       pos = (0, 2))
02299         gridSizer.Add(item = self.tbottom,
02300                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02301                       wx.ALL, border = 5, pos = (1, 2))
02302         # tbres
02303         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("T-B resolution")),
02304                       flag = wx.ALIGN_CENTER | 
02305                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
02306                       pos = (0, 3))
02307         gridSizer.Add(item = self.ttbres,
02308                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02309                       wx.ALL, border = 5, pos = (1, 3))
02310 
02311         # res
02312         #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D N-S resolution")),
02313         #                       flag = wx.ALIGN_CENTER |
02314         #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
02315         #                       pos = (2, 1))
02316         #         gridSizer.Add(item = self.tnsres3,
02317         #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02318         #                       wx.ALL, border = 5, pos = (3, 1))
02319         #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D E-W resolution")),
02320         #                       flag = wx.ALIGN_CENTER |
02321         #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
02322         #                       pos = (2, 3))
02323         #         gridSizer.Add(item = self.tewres3,
02324         #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02325         #                       wx.ALL, border = 5, pos = (3, 3))
02326 
02327         # rows/cols/cells
02328         gridSizer.Add(item = self.ldepth,
02329                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
02330                       wx.ALL, border = 5, pos = (2, 1))
02331 
02332         gridSizer.Add(item = self.lcells3,
02333                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
02334                       wx.ALL, border = 5, pos = (2, 2))
02335 
02336         border.Add(item = gridSizer, proportion = 1,
02337                    flag = wx.ALL | wx.ALIGN_CENTER | wx.EXPAND, border = 5)
02338 
02339         pane.SetSizer(border)
02340         border.Fit(pane)
02341 
02342     def OnSettings3DPaneChanged(self, event):
02343         """!Collapse 3D settings box"""
02344 
02345         if self.settings3D.IsExpanded():
02346             self.settings3D.SetLabel(self.infoCollapseLabelCol)
02347             self.Layout()
02348             self.SetSize(self.GetBestSize())
02349             self.SetMinSize(self.GetSize())
02350         else:
02351             self.settings3D.SetLabel(self.infoCollapseLabelExp)
02352             self.Layout()
02353             self.SetSize(self.minWindowSize)
02354             self.SetMinSize(self.minWindowSize)
02355 
02356         self.SendSizeEvent()
02357 
02358     def __DoLayout(self, panel):
02359         """!Window layout"""
02360         frameSizer = wx.BoxSizer(wx.VERTICAL)
02361         gridSizer = wx.GridBagSizer(vgap = 0, hgap = 0)
02362         settings3DSizer = wx.BoxSizer(wx.VERTICAL)
02363         buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
02364 
02365         # north
02366         gridSizer.Add(item = self.MakeLabel(text = _("North"), parent = panel),
02367                       flag = wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL |
02368                       wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (0, 2))
02369         gridSizer.Add(item = self.tnorth,
02370                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02371                       wx.ALIGN_CENTER_VERTICAL |
02372                       wx.ALL, border = 5, pos = (1, 2))
02373         # west
02374         gridSizer.Add(item = self.MakeLabel(text = _("West"), parent = panel),
02375                       flag = wx.ALIGN_RIGHT |
02376                       wx.ALIGN_CENTER_VERTICAL |
02377                       wx.LEFT | wx.TOP | wx.BOTTOM, border = 5, pos = (2, 0))
02378         gridSizer.Add(item = self.twest,
02379                       flag = wx.ALIGN_RIGHT |
02380                       wx.ALIGN_CENTER_VERTICAL |
02381                       wx.ALL, border = 5,  pos = (2, 1))
02382 
02383         gridSizer.Add(item = wx.StaticBitmap(panel, wx.ID_ANY, self.img, (-1, -1),
02384                                            (self.img.GetWidth(), self.img.GetHeight())),
02385                       flag = wx.ALIGN_CENTER |
02386                       wx.ALIGN_CENTER_VERTICAL |
02387                       wx.ALL, border = 5, pos = (2, 2))
02388 
02389         # east
02390         gridSizer.Add(item = self.teast,
02391                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02392                       wx.ALIGN_CENTER_VERTICAL |
02393                       wx.ALL, border = 5,  pos = (2, 3))
02394         gridSizer.Add(item = self.MakeLabel(text = _("East"), parent = panel),
02395                       flag = wx.ALIGN_LEFT |
02396                       wx.ALIGN_CENTER_VERTICAL |
02397                       wx.RIGHT | wx.TOP | wx.BOTTOM, border = 5, pos = (2, 4))
02398         # south
02399         gridSizer.Add(item = self.tsouth,
02400                       flag = wx.ALIGN_CENTER_HORIZONTAL |
02401                       wx.ALIGN_CENTER_VERTICAL |
02402                       wx.ALL, border = 5, pos = (3, 2))
02403         gridSizer.Add(item = self.MakeLabel(text = _("South"), parent = panel),
02404                       flag = wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL |
02405                       wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5, pos = (4, 2))
02406         # ns-res
02407         gridSizer.Add(item = self.MakeLabel(text = _("N-S resolution"), parent = panel),
02408                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
02409                       wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (5, 1))
02410         gridSizer.Add(item = self.tnsres,
02411                       flag = wx.ALIGN_RIGHT |
02412                       wx.ALIGN_CENTER_VERTICAL |
02413                       wx.ALL, border = 5,  pos = (6, 1))
02414         # ew-res
02415         gridSizer.Add(item = self.MakeLabel(text = _("E-W resolution"), parent = panel),
02416                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
02417                       wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (5, 3))
02418         gridSizer.Add(item = self.tewres,
02419                       flag = wx.ALIGN_RIGHT |
02420                       wx.ALIGN_CENTER_VERTICAL |
02421                       wx.ALL, border = 5,  pos = (6, 3))
02422         # rows/cols/cells
02423         gridSizer.Add(item = self.lrows,
02424                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
02425                       wx.ALL, border = 5, pos = (7, 1))
02426 
02427         gridSizer.Add(item = self.lcells,
02428                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
02429                       wx.ALL, border = 5, pos = (7, 2))
02430 
02431         gridSizer.Add(item = self.lcols,
02432                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
02433                       wx.ALL, border = 5, pos = (7, 3))
02434 
02435         # 3D
02436         settings3DSizer.Add(item = self.settings3D,
02437                             flag = wx.ALL,
02438                             border = 5)
02439 
02440         # buttons
02441         buttonSizer.Add(item = self.bcancel, proportion = 1,
02442                         flag = wx.ALIGN_RIGHT |
02443                         wx.ALIGN_CENTER_VERTICAL |
02444                         wx.ALL, border = 10)
02445         buttonSizer.Add(item = self.bset, proportion = 1,
02446                         flag = wx.ALIGN_CENTER |
02447                         wx.ALIGN_CENTER_VERTICAL |
02448                         wx.ALL, border = 10)
02449 
02450         frameSizer.Add(item = gridSizer, proportion = 1,
02451                        flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
02452         frameSizer.Add(item = settings3DSizer, proportion = 0,
02453                        flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
02454         frameSizer.Add(item = buttonSizer, proportion = 0,
02455                        flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
02456 
02457         self.SetAutoLayout(True)
02458         panel.SetSizer(frameSizer)
02459         frameSizer.Fit(panel)
02460         self.Layout()
02461 
02462     def OnValue(self, event):
02463         """!Set given value"""
02464         try:
02465             if event.GetId() == self.tnorth.GetId():
02466                 self.north = float(event.GetString())
02467             elif event.GetId() == self.tsouth.GetId():
02468                 self.south = float(event.GetString())
02469             elif event.GetId() == self.teast.GetId():
02470                 self.east = float(event.GetString())
02471             elif event.GetId() == self.twest.GetId():
02472                 self.west = float(event.GetString())
02473             elif event.GetId() == self.tnsres.GetId():
02474                 self.nsres = float(event.GetString())
02475             elif event.GetId() == self.tewres.GetId():
02476                 self.ewres = float(event.GetString())
02477             elif event.GetId() == self.ttop.GetId():
02478                 self.top = float(event.GetString())
02479             elif event.GetId() == self.tbottom.GetId():
02480                 self.bottom = float(event.GetString())
02481             #             elif event.GetId() == self.tnsres3.GetId():
02482             #                 self.nsres3 = float(event.GetString())
02483             #             elif event.GetId() == self.tewres3.GetId():
02484             #                 self.ewres3 = float(event.GetString())
02485             elif event.GetId() == self.ttbres.GetId():
02486                 self.tbres = float(event.GetString())
02487 
02488             self.__UpdateInfo()
02489 
02490         except ValueError, e:
02491             if len(event.GetString()) > 0 and event.GetString() != '-':
02492                 dlg = wx.MessageBox(parent = self,
02493                                     message = _("Invalid value: %s") % e,
02494                                     caption = _("Error"),
02495                                     style = wx.OK | wx.ICON_ERROR)
02496                 # reset values
02497                 self.tnorth.SetValue(str(self.north))
02498                 self.tsouth.SetValue(str(self.south))
02499                 self.teast.SetValue(str(self.east))
02500                 self.twest.SetValue(str(self.west))
02501                 self.tnsres.SetValue(str(self.nsres))
02502                 self.tewres.SetValue(str(self.ewres))
02503                 self.ttop.SetValue(str(self.top))
02504                 self.tbottom.SetValue(str(self.bottom))
02505                 self.ttbres.SetValue(str(self.tbres))
02506                 # self.tnsres3.SetValue(str(self.nsres3))
02507                 # self.tewres3.SetValue(str(self.ewres3))
02508 
02509         event.Skip()
02510 
02511     def __UpdateInfo(self):
02512         """!Update number of rows/cols/cells"""
02513         self.rows = int((self.north - self.south) / self.nsres)
02514         self.cols = int((self.east - self.west) / self.ewres)
02515         self.cells = self.rows * self.cols
02516 
02517         self.depth = int((self.top - self.bottom) / self.tbres)
02518         self.cells3 = self.rows * self.cols * self.depth
02519 
02520         # 2D
02521         self.lrows.SetLabel(_("Rows: %d") % self.rows)
02522         self.lcols.SetLabel(_("Cols: %d") % self.cols)
02523         self.lcells.SetLabel(_("Cells: %d") % self.cells)
02524         # 3D
02525         self.ldepth.SetLabel(_("Depth: %d" % self.depth))
02526         self.lcells3.SetLabel(_("3D Cells: %d" % self.cells3))
02527 
02528     def OnSetButton(self, event = None):
02529         """!Set default region"""
02530         ret = gcmd.RunCommand('g.region',
02531                               flags = 'sgpa',
02532                               n = self.north,
02533                               s = self.south,
02534                               e = self.east,
02535                               w = self.west,
02536                               nsres = self.nsres,
02537                               ewres = self.ewres,
02538                               t = self.top,
02539                               b = self.bottom,
02540                               tbres = self.tbres)
02541         if ret == 0:
02542             self.Destroy()
02543 
02544     def OnCancel(self, event):
02545         self.Destroy()
02546         
02547 class TransList(wx.VListBox):
02548     """!Creates a multiline listbox for selecting datum transforms"""
02549         
02550     def OnDrawItem(self, dc, rect, n):
02551         if self.GetSelection() == n:
02552             c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
02553         else:
02554             c = self.GetForegroundColour()
02555         dc.SetFont(self.GetFont())
02556         dc.SetTextForeground(c)
02557         dc.DrawLabel(self._getItemText(n), rect,
02558                      wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
02559 
02560     def OnMeasureItem(self, n):
02561         height = 0
02562         if self._getItemText(n) == None:
02563             return
02564         for line in self._getItemText(n).splitlines():
02565             w, h = self.GetTextExtent(line)
02566             height += h
02567         return height + 5
02568 
02569     def _getItemText(self, item):
02570         global transformlist
02571         transitem = transformlist[item]
02572         if transitem.strip() !='':
02573             return transitem
02574 
02575 
02576 class SelectTransformDialog(wx.Dialog):
02577     """!Dialog for selecting datum transformations"""
02578     def __init__(self, parent, transforms, title = _("Select datum transformation"),
02579                  pos = wx.DefaultPosition, size = wx.DefaultSize, 
02580                  style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
02581 
02582         wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
02583 
02584         global transformlist
02585         self.CentreOnParent()
02586         
02587         # default transform number
02588         self.transnum = 0
02589         
02590         panel = scrolled.ScrolledPanel(self, wx.ID_ANY)
02591         sizer = wx.BoxSizer(wx.VERTICAL)
02592 
02593         #
02594         # set panel sizer
02595         #
02596         panel.SetSizer(sizer)
02597         panel.SetupScrolling()
02598 
02599         #
02600         # dialog body
02601         #
02602         bodyBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
02603                                label = " %s " % _("Select from list of datum transformations"))
02604         bodySizer = wx.StaticBoxSizer(bodyBox)       
02605         
02606         # add no transform option
02607         transforms = '---\n\n0\nDo not apply any datum transformations\n\n' + transforms
02608         
02609         transformlist = transforms.split('---')
02610         tlistlen = len(transformlist)
02611         
02612         # calculate size for transform list
02613         height = 0
02614         width = 0
02615         for line in transforms.splitlines():
02616             w, h = self.GetTextExtent(line)
02617             height += h
02618             width = max(width, w)
02619             
02620         height = height + 5
02621         if height > 400: height = 400
02622         width = width + 5
02623         if width > 400: width = 400
02624 
02625         #
02626         # VListBox for displaying and selecting transformations
02627         #
02628         self.translist = TransList(panel, id = -1, size = (width, height), style = wx.SUNKEN_BORDER)
02629         self.translist.SetItemCount(tlistlen)
02630         self.translist.SetSelection(2)
02631         self.translist.SetFocus()
02632         
02633         self.Bind(wx.EVT_LISTBOX, self.ClickTrans, self.translist)
02634 
02635         bodySizer.Add(item = self.translist, proportion = 1, flag = wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
02636 
02637         #
02638         # buttons
02639         #
02640         btnsizer = wx.StdDialogButtonSizer()
02641 
02642         btn = wx.Button(parent = panel, id = wx.ID_OK)
02643         btn.SetDefault()
02644         btnsizer.AddButton(btn)
02645 
02646         btn = wx.Button(parent = panel, id = wx.ID_CANCEL)
02647         btnsizer.AddButton(btn)
02648         btnsizer.Realize()
02649 
02650         sizer.Add(item = bodySizer, proportion = 1,
02651                   flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
02652 
02653         sizer.Add(item = btnsizer, proportion = 0,
02654                   flag =  wx.ALL | wx.ALIGN_RIGHT, border = 5)
02655 
02656         sizer.Fit(panel)
02657 
02658         self.SetSize(self.GetBestSize())
02659         self.Layout()
02660         
02661     def ClickTrans(self, event):
02662         """!Get the number of the datum transform to use in g.proj"""
02663         self.transnum = event.GetSelection()
02664         self.transnum = self.transnum - 1
02665     
02666     def GetTransform(self):
02667         """!Get the number of the datum transform to use in g.proj"""
02668         self.transnum = self.translist.GetSelection()
02669         self.transnum = self.transnum - 1
02670         return self.transnum
02671 
02672 if __name__ == "__main__":
02673     import gettext
02674     gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
02675     app = wx.PySimpleApp()
02676     gWizard = RegionDef(None)
02677     gWizzard.Show()
02678     app.MainLoop()
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines