1""" 2@package location_wizard.wizard 3 4@brief Location wizard - creates a new GRASS Location. User can choose 5from multiple methods. 6 7Classes: 8 - wizard::TitledPage 9 - wizard::DatabasePage 10 - wizard::CoordinateSystemPage 11 - wizard::ProjectionsPage 12 - wizard::ItemList 13 - wizard::ProjParamsPage 14 - wizard::DatumPage 15 - wizard::EllipsePage 16 - wizard::GeoreferencedFilePage 17 - wizard::WKTPage 18 - wizard::EPSGPage 19 - wizard::IAUPage 20 - wizard::CustomPage 21 - wizard::SummaryPage 22 - wizard::LocationWizard 23 - wizard::WizardWithHelpButton 24 25(C) 2007-2016 by the GRASS Development Team 26 27This program is free software under the GNU General Public License 28(>=v2). Read the file COPYING that comes with GRASS for details. 29 30@author Michael Barton 31@author Jachym Cepicky 32@author Martin Landa <landa.martin gmail.com> 33@author Hamish Bowman (planetary ellipsoids) 34""" 35import os 36import sys 37import locale 38import six 39 40import wx 41import wx.lib.mixins.listctrl as listmix 42from core import globalvar 43if globalvar.wxPythonPhoenix: 44 from wx import adv as wiz 45 from wx.adv import Wizard 46 from wx.adv import WizardPageSimple 47else: 48 from wx import wizard as wiz 49 from wx.wizard import Wizard 50 from wx.wizard import WizardPageSimple 51import wx.lib.scrolledpanel as scrolled 52 53from core import utils 54from core.utils import cmp 55from core.gcmd import RunCommand, GError, GMessage, GWarning 56from gui_core.widgets import GenericValidator 57from gui_core.wrap import SpinCtrl, SearchCtrl, StaticText, \ 58 TextCtrl, Button, CheckBox, StaticBox, NewId, ListCtrl 59from location_wizard.base import BaseClass 60from location_wizard.dialogs import SelectTransformDialog 61 62from grass.script import decode 63from grass.script import core as grass 64from grass.exceptions import OpenError 65 66global coordsys 67global north 68global south 69global east 70global west 71global resolution 72global wizerror 73global translist 74 75if globalvar.CheckWxVersion(version=[4, 1, 0]): 76 search_cancel_evt = wx.EVT_SEARCH_CANCEL 77else: 78 search_cancel_evt = wx.EVT_SEARCHCTRL_CANCEL_BTN 79 80 81class TitledPage(WizardPageSimple): 82 """Class to make wizard pages. Generic methods to make labels, 83 text entries, and buttons. 84 """ 85 86 def __init__(self, parent, title): 87 self.page = WizardPageSimple.__init__(self, parent) 88 89 # page title 90 self.title = StaticText(parent=self, id=wx.ID_ANY, label=title, 91 style=wx.ALIGN_CENTRE_HORIZONTAL) 92 self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD)) 93 # main sizers 94 self.pagesizer = wx.BoxSizer(wx.VERTICAL) 95 self.sizer = wx.GridBagSizer(vgap=0, hgap=0) 96 self.sizer.SetCols(5) 97 self.sizer.SetRows(6) 98 99 def DoLayout(self): 100 """Do page layout""" 101 self.pagesizer.Add(self.title, proportion=0, 102 flag=wx.EXPAND | wx.ALL, 103 border=5) 104 self.pagesizer.Add(wx.StaticLine(self, -1), proportion=0, 105 flag=wx.EXPAND | wx.ALL, 106 border=0) 107 self.pagesizer.Add(self.sizer, proportion=1, 108 flag=wx.EXPAND) 109 110 self.SetAutoLayout(True) 111 self.SetSizer(self.pagesizer) 112 self.Layout() 113 114 def MakeLabel(self, text="", style=wx.ALIGN_LEFT, 115 parent=None, tooltip=None): 116 """Make aligned label""" 117 if not parent: 118 parent = self 119 label = StaticText(parent=parent, id=wx.ID_ANY, label=text, 120 style=style) 121 if tooltip: 122 label.SetToolTip(tooltip) 123 return label 124 125 def MakeTextCtrl(self, text='', size=(100, -1), 126 style=0, parent=None, tooltip=None): 127 """Generic text control""" 128 if not parent: 129 parent = self 130 textCtrl = TextCtrl(parent=parent, id=wx.ID_ANY, value=text, 131 size=size, style=style) 132 if tooltip: 133 textCtrl.SetToolTip(tooltip) 134 return textCtrl 135 136 def MakeButton(self, text, id=wx.ID_ANY, size=(-1, -1), 137 parent=None, tooltip=None): 138 """Generic button""" 139 if not parent: 140 parent = self 141 button = Button(parent=parent, id=id, label=text, 142 size=size) 143 if tooltip: 144 button.SetToolTip(tooltip) 145 return button 146 147 def MakeCheckBox(self, text, id=wx.ID_ANY, size=(-1, -1), 148 parent=None, tooltip=None): 149 """Generic checkbox""" 150 if not parent: 151 parent = self 152 chbox = CheckBox(parent=parent, id=id, label=text, 153 size=size) 154 if tooltip: 155 chbox.SetToolTip(tooltip) 156 return chbox 157 158 159class DatabasePage(TitledPage): 160 """Wizard page for setting GIS data directory and location name""" 161 162 def __init__(self, wizard, parent, grassdatabase): 163 TitledPage.__init__(self, wizard, _( 164 "Define GRASS Database and Location Name")) 165 166 self.grassdatabase = grassdatabase 167 self.location = '' 168 self.locTitle = '' 169 170 # buttons 171 self.bbrowse = self.MakeButton(_("Browse")) 172 173 # text controls 174 self.tgisdbase = self.MakeTextCtrl(grassdatabase, size=(300, -1)) 175 self.tlocation = self.MakeTextCtrl("newLocation", size=(300, -1)) 176 self.tlocation.SetFocus() 177 self.tlocation.SetValidator( 178 GenericValidator( 179 grass.legal_name, 180 self._nameValidationFailed)) 181 self.tlocTitle = self.MakeTextCtrl(size=(400, -1)) 182 183 # checkbox 184 self.tlocRegion = self.MakeCheckBox(_("Set default region extent and resolution"), 185 tooltip=_("This option allows setting default " 186 "computation region immediately after " 187 "new location is created. Default " 188 "computation region can be defined later " 189 "using g.region based on imported data.")) 190 191 self.tlocUserMapset = self.MakeCheckBox(_("Create user mapset"), 192 tooltip=_("This option allows creating user " 193 "mapset immediately after new location " 194 "is created. Note that GRASS always creates " 195 "PERMANENT mapset.")) 196 197 # layout 198 self.sizer.Add(self.MakeLabel(_("GIS Data Directory:")), 199 flag=wx.ALIGN_RIGHT | 200 wx.ALIGN_CENTER_VERTICAL | 201 wx.ALL, border=5, 202 pos=(1, 1)) 203 self.sizer.Add(self.tgisdbase, 204 flag=wx.ALIGN_LEFT | 205 wx.ALIGN_CENTER_VERTICAL | 206 wx.ALL, border=5, 207 pos=(1, 2)) 208 self.sizer.Add(self.bbrowse, 209 flag=wx.ALIGN_LEFT | 210 wx.ALIGN_CENTER_VERTICAL | 211 wx.ALL, border=5, 212 pos=(1, 3)) 213 214 self.sizer.Add( 215 self.MakeLabel( 216 "%s:" % 217 _("Project Location"), 218 tooltip=_("Name of location directory in GIS Data Directory")), 219 flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 220 border=5, 221 pos=(2, 1) 222 ) 223 self.sizer.Add(self.tlocation, 224 flag=wx.ALIGN_LEFT | 225 wx.ALIGN_CENTER_VERTICAL | 226 wx.ALL, border=5, 227 pos=(2, 2)) 228 229 self.sizer.Add( 230 self.MakeLabel( 231 "%s:" % 232 _("Location Title"), 233 tooltip=_( 234 "Optional location title, " 235 "you can leave this field blank.")), 236 flag=wx.ALIGN_RIGHT | wx.ALIGN_TOP | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 237 border=5, 238 pos=(3, 1) 239 ) 240 self.sizer.Add(self.tlocTitle, 241 flag=wx.ALIGN_LEFT | 242 wx.ALIGN_CENTER_VERTICAL | 243 wx.ALL, border=5, 244 pos=(3, 2), span=(1, 2)) 245 self.sizer.Add(self.tlocRegion, 246 flag=wx.ALIGN_LEFT | 247 wx.ALIGN_CENTER_VERTICAL | 248 wx.ALL, border=5, 249 pos=(4, 2), span=(1, 2)) 250 self.sizer.Add(self.tlocUserMapset, 251 flag=wx.ALIGN_LEFT | 252 wx.ALIGN_CENTER_VERTICAL | 253 wx.ALL, border=5, 254 pos=(5, 2), span=(1, 2)) 255 self.sizer.AddGrowableCol(3) 256 257 # bindings 258 self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.bbrowse) 259 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 260 self.tgisdbase.Bind(wx.EVT_TEXT, self.OnChangeName) 261 self.tlocation.Bind(wx.EVT_TEXT, self.OnChangeName) 262 263 def _nameValidationFailed(self, ctrl): 264 message = _( 265 "Name <%(name)s> is not a valid name for location. " 266 "Please use only ASCII characters excluding %(chars)s " 267 "and space.") % { 268 'name': ctrl.GetValue(), 269 'chars': '/"\'@,=*~'} 270 GError( 271 parent=self, 272 message=message, 273 caption=_("Invalid location name")) 274 275 def OnChangeName(self, event): 276 """Name for new location was changed""" 277 nextButton = wx.FindWindowById(wx.ID_FORWARD) 278 if len(event.GetString()) > 0: 279 if not nextButton.IsEnabled(): 280 nextButton.Enable() 281 else: 282 nextButton.Disable() 283 284 event.Skip() 285 286 def OnBrowse(self, event): 287 """Choose GRASS data directory""" 288 dlg = wx.DirDialog(self, _("Choose GRASS data directory:"), 289 os.getcwd(), wx.DD_DEFAULT_STYLE) 290 if dlg.ShowModal() == wx.ID_OK: 291 self.grassdatabase = dlg.GetPath() 292 self.tgisdbase.SetValue(self.grassdatabase) 293 294 dlg.Destroy() 295 296 def OnPageChanging(self, event=None): 297 error = None 298 if os.path.isdir( 299 os.path.join( 300 self.tgisdbase.GetValue(), 301 self.tlocation.GetValue())): 302 error = _("Location already exists in GRASS Database.") 303 304 if error: 305 GError(parent=self, 306 message="%s <%s>.%s%s" % (_("Unable to create location"), 307 str(self.tlocation.GetValue()), 308 os.linesep, 309 error)) 310 event.Veto() 311 return 312 313 self.location = self.tlocation.GetValue() 314 self.grassdatabase = self.tgisdbase.GetValue() 315 self.locTitle = self.tlocTitle.GetValue() 316 if os.linesep in self.locTitle or \ 317 len(self.locTitle) > 255: 318 GWarning( 319 parent=self, message=_( 320 "Title of the location is limited only to one line and " 321 "256 characters. The rest of the text will be ignored.")) 322 self.locTitle = self.locTitle.split(os.linesep)[0][:255] 323 324 325class CoordinateSystemPage(TitledPage): 326 """Wizard page for choosing method for location creation""" 327 328 def __init__(self, wizard, parent): 329 TitledPage.__init__(self, wizard, _( 330 "Choose method for creating a new location")) 331 332 self.parent = parent 333 global coordsys 334 335 # toggles 336 self.radioEpsg = wx.RadioButton(parent=self, id=wx.ID_ANY, label=_( 337 "Select EPSG code of spatial reference system"), style=wx.RB_GROUP) 338 #self.radioIau = wx.RadioButton( 339 # parent=self, id=wx.ID_ANY, 340 # label=_("Select IAU code of spatial reference system")) 341 self.radioFile = wx.RadioButton( 342 parent=self, id=wx.ID_ANY, label=_( 343 "Read projection and datum terms from a " 344 "georeferenced data file")) 345 self.radioWkt = wx.RadioButton( 346 parent=self, id=wx.ID_ANY, label=_( 347 "Read projection and datum terms from a " 348 "Well Known Text (WKT) .prj file")) 349 self.radioSrs = wx.RadioButton(parent=self, id=wx.ID_ANY, label=_( 350 "Select coordinate system parameters from a list")) 351 self.radioProj = wx.RadioButton( 352 parent=self, id=wx.ID_ANY, label=_( 353 "Specify projection and datum terms using custom " 354 "PROJ.4 parameters")) 355 self.radioXy = wx.RadioButton(parent=self, id=wx.ID_ANY, label=_( 356 "Create a generic Cartesian coordinate system (XY)")) 357 358 # layout 359 self.sizer.SetVGap(10) 360 self.sizer.Add(StaticText(parent=self, label=_("Simple methods:")), 361 flag=wx.ALIGN_LEFT, pos=(1, 1)) 362 self.sizer.Add(self.radioEpsg, 363 flag=wx.ALIGN_LEFT, pos=(2, 1)) 364 #self.sizer.Add(self.radioIau, 365 # flag=wx.ALIGN_LEFT, pos=(1, 1)) 366 self.sizer.Add(self.radioFile, 367 flag=wx.ALIGN_LEFT, pos=(3, 1)) 368 self.sizer.Add(self.radioWkt, 369 flag=wx.ALIGN_LEFT, pos=(4, 1)) 370 self.sizer.Add(self.radioXy, 371 flag=wx.ALIGN_LEFT, pos=(5, 1)) 372 self.sizer.Add(StaticText(parent=self, label=_("Advanced methods:")), 373 flag=wx.ALIGN_LEFT, pos=(6, 1)) 374 self.sizer.Add(self.radioSrs, 375 flag=wx.ALIGN_LEFT, pos=(7, 1)) 376 self.sizer.Add(self.radioProj, 377 flag=wx.ALIGN_LEFT, pos=(8, 1)) 378 self.sizer.AddGrowableCol(1) 379 380 # bindings 381 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioEpsg.GetId()) 382 #self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioIau.GetId()) 383 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioFile.GetId()) 384 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioWkt.GetId()) 385 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioSrs.GetId()) 386 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioProj.GetId()) 387 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioXy.GetId()) 388 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 389 390 def OnEnterPage(self, event): 391 global coordsys 392 393 if not coordsys: 394 coordsys = "epsg" 395 self.radioEpsg.SetValue(True) 396 else: 397 if coordsys == 'proj': 398 self.radioSrs.SetValue(True) 399 if coordsys == "epsg": 400 self.radioEpsg.SetValue(True) 401 #if coordsys == "iau": 402 # self.radioIau.SetValue(True) 403 if coordsys == "file": 404 self.radioFile.SetValue(True) 405 if coordsys == "wkt": 406 self.radioWkt.SetValue(True) 407 if coordsys == "custom": 408 self.radioProj.SetValue(True) 409 if coordsys == "xy": 410 self.radioXy.SetValue(True) 411 412 if event.GetDirection(): 413 if coordsys == 'proj': 414 self.SetNext(self.parent.projpage) 415 self.parent.sumpage.SetPrev(self.parent.datumpage) 416 if coordsys == "epsg": 417 self.SetNext(self.parent.epsgpage) 418 self.parent.sumpage.SetPrev(self.parent.epsgpage) 419 #if coordsys == "iau": 420 # self.SetNext(self.parent.iaupage) 421 # self.parent.sumpage.SetPrev(self.parent.iaupage) 422 if coordsys == "file": 423 self.SetNext(self.parent.filepage) 424 self.parent.sumpage.SetPrev(self.parent.filepage) 425 if coordsys == "wkt": 426 self.SetNext(self.parent.wktpage) 427 self.parent.sumpage.SetPrev(self.parent.wktpage) 428 if coordsys == "custom": 429 self.SetNext(self.parent.custompage) 430 self.parent.sumpage.SetPrev(self.parent.custompage) 431 if coordsys == "xy": 432 self.SetNext(self.parent.sumpage) 433 self.parent.sumpage.SetPrev(self.parent.csystemspage) 434 435 if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled(): 436 wx.FindWindowById(wx.ID_FORWARD).Enable() 437 438 def SetVal(self, event): 439 """Choose method""" 440 global coordsys 441 if event.GetId() == self.radioSrs.GetId(): 442 coordsys = "proj" 443 self.SetNext(self.parent.projpage) 444 self.parent.sumpage.SetPrev(self.parent.datumpage) 445 #elif event.GetId() == self.radioIau.GetId(): 446 # coordsys = "iau" 447 # self.SetNext(self.parent.iaupage) 448 # self.parent.sumpage.SetPrev(self.parent.iaupage) 449 elif event.GetId() == self.radioEpsg.GetId(): 450 coordsys = "epsg" 451 self.SetNext(self.parent.epsgpage) 452 self.parent.sumpage.SetPrev(self.parent.epsgpage) 453 elif event.GetId() == self.radioFile.GetId(): 454 coordsys = "file" 455 self.SetNext(self.parent.filepage) 456 self.parent.sumpage.SetPrev(self.parent.filepage) 457 elif event.GetId() == self.radioWkt.GetId(): 458 coordsys = "wkt" 459 self.SetNext(self.parent.wktpage) 460 self.parent.sumpage.SetPrev(self.parent.wktpage) 461 elif event.GetId() == self.radioProj.GetId(): 462 coordsys = "custom" 463 self.SetNext(self.parent.custompage) 464 self.parent.sumpage.SetPrev(self.parent.custompage) 465 elif event.GetId() == self.radioXy.GetId(): 466 coordsys = "xy" 467 self.SetNext(self.parent.sumpage) 468 self.parent.sumpage.SetPrev(self.parent.csystemspage) 469 470 471class ProjectionsPage(TitledPage): 472 """Wizard page for selecting projection (select coordinate system option)""" 473 474 def __init__(self, wizard, parent): 475 TitledPage.__init__(self, wizard, _("Choose projection")) 476 477 self.parent = parent 478 self.proj = '' 479 self.projdesc = '' 480 self.p4proj = '' 481 482 # text input 483 self.tproj = self.MakeTextCtrl("", size=(200, -1)) 484 485 # search box 486 self.searchb = SearchCtrl(self, size=(200, -1), 487 style=wx.TE_PROCESS_ENTER) 488 self.searchb.ShowCancelButton(True) 489 490 # projection list 491 self.projlist = ItemList(self, data=list(self.parent.projdesc.items()), 492 columns=[_('Code'), _('Description')]) 493 self.projlist.resizeLastColumn(30) 494 495 # layout 496 self.sizer.Add(self.MakeLabel(_("Projection code:")), 497 flag=wx.ALIGN_LEFT | 498 wx.ALIGN_CENTER_VERTICAL | 499 wx.ALL, border=5, pos=(1, 1)) 500 self.sizer.Add(self.tproj, 501 flag=wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL, 502 border=5, pos=(1, 2)) 503 504 self.sizer.Add(self.MakeLabel(_("Search in description:")), 505 flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 506 border=5, pos=(2, 1)) 507 self.sizer.Add(self.searchb, 508 flag=wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL, 509 border=5, pos=(2, 2)) 510 511 self.sizer.Add(self.projlist, 512 flag=wx.EXPAND | 513 wx.ALIGN_LEFT | 514 wx.ALL, border=5, pos=(3, 1), span=(1, 3)) 515 self.sizer.AddGrowableCol(3) 516 self.sizer.AddGrowableRow(3) 517 518 # events 519 self.tproj.Bind(wx.EVT_TEXT, self.OnText) 520 self.searchb.Bind(wx.EVT_TEXT, self.OnSearch) 521 self.searchb.Bind(search_cancel_evt, self.OnSearchCancel) 522 self.projlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) 523 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 524 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 525 526 def OnPageChanging(self, event): 527 if event.GetDirection() and self.proj not in self.parent.projections.keys(): 528 event.Veto() 529 530 def OnText(self, event): 531 """Projection name changed""" 532 self.proj = event.GetString().lower() 533 self.p4proj = '' 534 nextButton = wx.FindWindowById(wx.ID_FORWARD) 535 if self.proj not in self.parent.projections.keys() and nextButton.IsEnabled(): 536 nextButton.Enable(False) 537 538 if self.proj in self.parent.projections.keys(): 539 if self.proj == 'stp': 540 wx.MessageBox( 541 'Currently State Plane projections must be selected using the ' 542 'text-based setup (g.setproj), or entered by EPSG code or ' 543 'custom PROJ.4 terms.', 'Warning', wx.ICON_WARNING) 544 self.proj = '' 545 self.tproj.SetValue(self.proj) 546 nextButton.Enable(False) 547 return 548 elif self.proj.lower() == 'll': 549 self.p4proj = '+proj=longlat' 550 else: 551 self.p4proj = '+proj=' + self.proj.lower() 552 self.projdesc = self.parent.projections[self.proj][0] 553 nextButton.Enable() 554 555 def OnEnterPage(self, event): 556 if len(self.proj) == 0: 557 # disable 'next' button by default 558 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 559 else: 560 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 561 562 event.Skip() 563 564 def OnSearch(self, event): 565 """Search projection by desc""" 566 search_str = event.GetString() 567 try: 568 self.proj, self.projdesc = self.projlist.Search( 569 index=[0, 1], pattern=search_str) 570 except: 571 self.proj = self.projdesc = '' 572 573 event.Skip() 574 575 def OnSearchCancel(self, event): 576 self.projlist.Search(index=None, pattern="") 577 event.Skip() 578 579 def OnItemSelected(self, event): 580 """Projection selected""" 581 index = event.GetIndex() 582 583 # set values 584 self.proj = self.projlist.GetItem(index, 0).GetText().lower() 585 self.tproj.SetValue(self.proj) 586 587 event.Skip() 588 589 590class ItemList(ListCtrl, 591 listmix.ListCtrlAutoWidthMixin, 592 listmix.ColumnSorterMixin): 593 """Generic list (for projections, ellipsoids, etc.)""" 594 595 def __init__(self, parent, columns, data=None): 596 ListCtrl.__init__(self, parent=parent, id=wx.ID_ANY, 597 style=wx.LC_REPORT | 598 wx.LC_VIRTUAL | 599 wx.LC_HRULES | 600 wx.LC_VRULES | 601 wx.LC_SINGLE_SEL | 602 wx.LC_SORT_ASCENDING, size=(550, 125)) 603 604 # original data or None 605 self.sourceData = data 606 607 # 608 # insert columns 609 # 610 i = 0 611 for column in columns: 612 self.InsertColumn(i, column) 613 i += 1 614 615 self.EnableAlternateRowColours() 616 617 if self.sourceData: 618 self.Populate() 619 620 for i in range(self.GetColumnCount()): 621 self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER) 622 if self.GetColumnWidth(i) < 80: 623 self.SetColumnWidth(i, 80) 624 625 # 626 # listmix 627 # 628 listmix.ListCtrlAutoWidthMixin.__init__(self) 629 listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount()) 630 631 self.il = wx.ImageList(16, 16) 632 self.sm_up = self.il.Add( 633 wx.ArtProvider.GetBitmap( 634 wx.ART_GO_UP, wx.ART_TOOLBAR, (16, 16))) 635 self.sm_dn = self.il.Add( 636 wx.ArtProvider.GetBitmap( 637 wx.ART_GO_DOWN, wx.ART_TOOLBAR, (16, 16))) 638 self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) 639 640 # 641 # sort by first column 642 # 643 if self.sourceData: 644 self.SortListItems(col=0, ascending=True) 645 646 # 647 # bindings 648 # 649 self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick) 650 651 def Populate(self, data=None, update=False): 652 """Populate list""" 653 self.itemDataMap = {} 654 self.itemIndexMap = [] 655 656 if data is None: 657 data = self.sourceData 658 elif update: 659 self.sourceData = data 660 661 try: 662 data = sorted(data) 663 self.DeleteAllItems() 664 row = 0 665 for value in data: 666 self.itemDataMap[row] = [value[0]] 667 for i in range(1, len(value)): 668 self.itemDataMap[row].append(value[i]) 669 self.itemIndexMap.append(row) 670 row += 1 671 672 self.SetItemCount(row) 673 674 # set column width 675 self.SetColumnWidth(0, 80) 676 self.SetColumnWidth(1, 300) 677 678 self.SendSizeEvent() 679 680 except Exception as e: 681 wx.MessageBox(parent=self, 682 message=_("Unable to read list: %s") % e, 683 caption=_("Error"), style=wx.OK | wx.ICON_ERROR) 684 685 def OnColumnClick(self, event): 686 """Sort by column""" 687 self._col = event.GetColumn() 688 689 # remove duplicated arrow symbol from column header 690 # FIXME: should be done automatically 691 info = wx.ListItem() 692 info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE 693 info.m_image = -1 694 for column in range(self.GetColumnCount()): 695 info.m_text = self.GetColumn(column).GetText() 696 self.SetColumn(column, info) 697 698 event.Skip() 699 700 def GetSortImages(self): 701 """Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py""" 702 return (self.sm_dn, self.sm_up) 703 704 def OnGetItemText(self, item, col): 705 """Get item text""" 706 index = self.itemIndexMap[item] 707 s = str(self.itemDataMap[index][col]) 708 return s 709 710 def OnGetItemImage(self, item): 711 return -1 712 713 def SortItems(self, sorter=cmp): 714 """Sort items""" 715 items = list(self.itemDataMap.keys()) 716 if sys.version_info[0] >= 3: 717 # not sure what Sorter is needed for 718 items.sort() 719 else: 720 items.sort(self.Sorter) 721 self.itemIndexMap = items 722 723 # redraw the list 724 self.Refresh() 725 726 def Sorter(self, key1, key2): 727 colName = self.GetColumn(self._col).GetText() 728 ascending = self._colSortFlag[self._col] 729 # convert always string 730 item1 = self.itemDataMap[key1][self._col] 731 item2 = self.itemDataMap[key2][self._col] 732 733 if isinstance(item1, type('')) or isinstance(item2, type('')): 734 cmpVal = locale.strcoll(str(item1), str(item2)) 735 else: 736 cmpVal = cmp(item1, item2) 737 738 # If the items are equal then pick something else to make the sort 739 # value unique 740 if cmpVal == 0: 741 cmpVal = cmp(*self.GetSecondarySortValues(self._col, key1, key2)) 742 743 if ascending: 744 return cmpVal 745 else: 746 return -cmpVal 747 748 def GetListCtrl(self): 749 """Used by listmix.ColumnSorterMixin""" 750 return self 751 752 def Search(self, index, pattern): 753 """Search projection by description 754 Return first found item or None 755 """ 756 if pattern == '': 757 self.Populate(self.sourceData) 758 return [] 759 760 data = [] 761 pattern = pattern.lower() 762 for i in range(len(self.sourceData)): 763 for idx in index: 764 try: 765 value = str(self.sourceData[i][idx]).lower() 766 if pattern in value: 767 data.append(self.sourceData[i]) 768 break 769 except UnicodeDecodeError: 770 # osgeo4w problem (should be fixed) 771 pass 772 773 self.Populate(data) 774 if len(data) > 0: 775 return data[0] 776 else: 777 return [] 778 779 780class ProjParamsPage(TitledPage): 781 """Wizard page for selecting method of setting coordinate system 782 parameters (select coordinate system option) 783 """ 784 785 def __init__(self, wizard, parent): 786 TitledPage.__init__(self, wizard, _("Choose projection parameters")) 787 global coordsys 788 789 self.parent = parent 790 self.panel = None 791 self.prjParamSizer = None 792 793 self.pparam = dict() 794 795 self.p4projparams = '' 796 self.projdesc = '' 797 798 radioSBox = StaticBox( 799 parent=self, id=wx.ID_ANY, label=" %s " % 800 _("Select datum or ellipsoid (next page)")) 801 radioSBSizer = wx.StaticBoxSizer(radioSBox) 802 self.sizer.Add(radioSBSizer, pos=(0, 1), 803 flag=wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border=10) 804 self.sizer.AddGrowableCol(1) 805 806 self.radio1 = wx.RadioButton( 807 parent=self, id=wx.ID_ANY, 808 label=_("Datum with associated ellipsoid"), 809 style=wx.RB_GROUP) 810 self.radioEpsg = wx.RadioButton(parent=self, id=wx.ID_ANY, 811 label=_("Ellipsoid only")) 812 813 # default button setting 814 if self.radio1.GetValue() == False and self.radioEpsg.GetValue() == False: 815 self.radio1.SetValue(True) 816 self.SetNext(self.parent.datumpage) 817 # self.parent.sumpage.SetPrev(self.parent.datumpage) 818 819 radioSBSizer.Add(self.radio1, 820 flag=wx.ALIGN_LEFT | wx.RIGHT, border=20) 821 radioSBSizer.Add(self.radioEpsg, 822 flag=wx.ALIGN_LEFT) 823 824 # bindings 825 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio1.GetId()) 826 self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radioEpsg.GetId()) 827 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) 828 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 829 830 def OnParamEntry(self, event): 831 """Parameter value changed""" 832 id = event.GetId() 833 val = event.GetString() 834 835 if id not in self.pparam: 836 event.Skip() 837 return 838 839 param = self.pparam[id] 840 win = self.FindWindowById(id) 841 if param['type'] == 'zone': 842 val = self.FindWindowById(id).GetValue() 843 if val < 1: 844 win.SetValue(1) 845 elif val > 60: 846 win.SetValue(60) 847 848 if param['type'] == 'bool': 849 param['value'] = event.GetSelection() 850 else: 851 param['value'] = val 852 853 event.Skip() 854 855 def OnPageChange(self, event=None): 856 """Go to next page""" 857 if event.GetDirection(): 858 self.p4projparams = '' 859 for id, param in six.iteritems(self.pparam): 860 if param['type'] == 'bool': 861 if param['value'] == False: 862 continue 863 else: 864 self.p4projparams += (' +' + param['proj4']) 865 else: 866 if param['value'] is None: 867 wx.MessageBox( 868 parent=self, 869 message=_('You must enter a value for %s') % 870 param['desc'], 871 caption=_('Error'), 872 style=wx.ICON_ERROR | wx.CENTRE) 873 event.Veto() 874 else: 875 self.p4projparams += (' +' + 876 param['proj4'] + 877 '=' + 878 str(param['value'])) 879 880 def OnEnterPage(self, event): 881 """Page entered""" 882 self.projdesc = self.parent.projections[self.parent.projpage.proj][0] 883 if self.prjParamSizer is None: 884 # entering page for the first time 885 self.paramSBox = StaticBox( 886 parent=self, 887 id=wx.ID_ANY, 888 label=_(" Enter parameters for %s projection ") % 889 self.projdesc) 890 paramSBSizer = wx.StaticBoxSizer(self.paramSBox) 891 892 self.panel = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY) 893 self.panel.SetupScrolling() 894 895 self.prjParamSizer = wx.GridBagSizer(vgap=0, hgap=0) 896 897 self.sizer.Add(paramSBSizer, pos=(1, 1), 898 flag=wx.EXPAND) 899 self.sizer.AddGrowableRow(1) 900 paramSBSizer.Add(self.panel, proportion=1, 901 flag=wx.EXPAND) 902 903 paramSBSizer.Fit(self.panel) 904 self.panel.SetSizer(self.prjParamSizer) 905 906 if event.GetDirection(): 907 self.prjParamSizer.Clear(True) 908 self.paramSBox.SetLabel( 909 _(" Enter parameters for %s projection ") % 910 self.projdesc) 911 self.pparam = dict() 912 row = 0 913 for paramgrp in self.parent.projections[ 914 self.parent.projpage.proj][1]: 915 # get parameters 916 id = NewId() 917 param = self.pparam[id] = { 918 'type': self.parent.paramdesc[ 919 paramgrp[0]][0], 'proj4': self.parent.paramdesc[ 920 paramgrp[0]][1], 'desc': self.parent.paramdesc[ 921 paramgrp[0]][2]} 922 923 # default values 924 if param['type'] == 'bool': 925 param['value'] = 0 926 elif param['type'] == 'zone': 927 param['value'] = 30 928 param['desc'] += ' (1-60)' 929 else: 930 param['value'] = paramgrp[2] 931 932 label = StaticText( 933 parent=self.panel, 934 id=wx.ID_ANY, 935 label=param['desc'], 936 style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE) 937 if param['type'] == 'bool': 938 win = wx.Choice(parent=self.panel, id=id, size=(100, -1), 939 choices=[_('No'), _('Yes')]) 940 win.SetSelection(param['value']) 941 win.Bind(wx.EVT_CHOICE, self.OnParamEntry) 942 elif param['type'] == 'zone': 943 win = SpinCtrl(parent=self.panel, id=id, 944 size=(100, -1), 945 style=wx.SP_ARROW_KEYS | wx.SP_WRAP, 946 min=1, max=60) 947 win.SetValue(param['value']) 948 win.Bind(wx.EVT_SPINCTRL, self.OnParamEntry) 949 win.Bind(wx.EVT_TEXT, self.OnParamEntry) 950 else: 951 win = TextCtrl(parent=self.panel, id=id, 952 value=param['value'], 953 size=(100, -1)) 954 win.Bind(wx.EVT_TEXT, self.OnParamEntry) 955 if paramgrp[1] == 'noask': 956 win.Enable(False) 957 958 self.prjParamSizer.Add(label, pos=(row, 1), 959 flag=wx.ALIGN_RIGHT | 960 wx.ALIGN_CENTER_VERTICAL | 961 wx.RIGHT, border=5) 962 self.prjParamSizer.Add(win, pos=(row, 2), 963 flag=wx.ALIGN_LEFT | 964 wx.ALIGN_CENTER_VERTICAL | 965 wx.LEFT, border=5) 966 row += 1 967 968 self.panel.SetSize(self.panel.GetBestSize()) 969 self.panel.Layout() 970 self.Layout() 971 self.Update() 972 973 if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled(): 974 wx.FindWindowById(wx.ID_FORWARD).Enable() 975 976 event.Skip() 977 978 def SetVal(self, event): 979 """Set value""" 980 if event.GetId() == self.radio1.GetId(): 981 self.SetNext(self.parent.datumpage) 982 self.parent.sumpage.SetPrev(self.parent.datumpage) 983 elif event.GetId() == self.radioEpsg.GetId(): 984 self.SetNext(self.parent.ellipsepage) 985 self.parent.sumpage.SetPrev(self.parent.ellipsepage) 986 987 988class DatumPage(TitledPage): 989 """Wizard page for selecting datum (with associated ellipsoid) 990 and datum transformation parameters (select coordinate system option) 991 """ 992 993 def __init__(self, wizard, parent): 994 TitledPage.__init__(self, wizard, _("Specify geodetic datum")) 995 996 self.parent = parent 997 self.datum = '' 998 self.datumdesc = '' 999 self.ellipse = '' 1000 self.datumparams = '' 1001 self.proj4params = '' 1002 1003 # text input 1004 self.tdatum = self.MakeTextCtrl("", size=(200, -1)) 1005 1006 # search box 1007 self.searchb = SearchCtrl(self, size=(200, -1), 1008 style=wx.TE_PROCESS_ENTER) 1009 self.searchb.ShowCancelButton(True) 1010 1011 # create list control for datum/elipsoid list 1012 data = [] 1013 for key in self.parent.datums.keys(): 1014 data.append([key, self.parent.datums[key][ 1015 0], self.parent.datums[key][1]]) 1016 self.datumlist = ItemList( 1017 self, data=data, columns=[ 1018 _('Code'), _('Ellipsoid'), _('Description')]) 1019 self.datumlist.resizeLastColumn(10) 1020 1021 # layout 1022 self.sizer.Add(self.MakeLabel(_("Datum code:")), 1023 flag=wx.ALIGN_LEFT | 1024 wx.ALIGN_CENTER_VERTICAL | 1025 wx.ALL, border=5, pos=(1, 1)) 1026 self.sizer.Add(self.tdatum, 1027 flag=wx.ALIGN_LEFT | 1028 wx.ALIGN_CENTER_VERTICAL | 1029 wx.ALL, border=5, pos=(1, 2)) 1030 1031 self.sizer.Add(self.MakeLabel(_("Search in description:")), 1032 flag=wx.ALIGN_LEFT | 1033 wx.ALIGN_CENTER_VERTICAL | 1034 wx.ALL, border=5, pos=(2, 1)) 1035 self.sizer.Add(self.searchb, 1036 flag=wx.ALIGN_LEFT | 1037 wx.ALIGN_CENTER_VERTICAL | 1038 wx.ALL, border=5, pos=(2, 2)) 1039 1040 self.sizer.Add(self.datumlist, 1041 flag=wx.EXPAND | 1042 wx.ALIGN_LEFT | 1043 wx.ALL, border=5, pos=(3, 1), span=(1, 4)) 1044 self.sizer.AddGrowableCol(4) 1045 self.sizer.AddGrowableRow(3) 1046 1047 # events 1048 self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected) 1049 self.searchb.Bind(wx.EVT_TEXT, self.OnDSearch) 1050 self.searchb.Bind(search_cancel_evt, self.OnSearchCancel) 1051 self.tdatum.Bind(wx.EVT_TEXT, self.OnDText) 1052 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 1053 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 1054 1055 # do page layout 1056 # self.DoLayout() 1057 1058 def OnPageChanging(self, event): 1059 self.proj4params = '' 1060 proj = self.parent.projpage.p4proj 1061 1062 if event.GetDirection(): 1063 if self.datum not in self.parent.datums: 1064 event.Veto() 1065 else: 1066 # check for datum tranforms 1067 # proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum 1068 ret = RunCommand('g.proj', 1069 read=True, 1070 proj4='%s' % proj, 1071 datum='%s' % self.datum, 1072 datum_trans='-1', 1073 flags='t') 1074# wx.Messagebox('here') 1075 if ret != '': 1076 dtrans = '' 1077 # open a dialog to select datum transform number 1078 dlg = SelectTransformDialog( 1079 self.parent.parent, transforms=ret) 1080 1081 if dlg.ShowModal() == wx.ID_OK: 1082 dtrans = dlg.GetTransform() 1083 if dtrans == '': 1084 dlg.Destroy() 1085 event.Veto() 1086 return 'Datum transform is required.' 1087 else: 1088 dlg.Destroy() 1089 event.Veto() 1090 return 'Datum transform is required.' 1091 1092 self.parent.datum_trans = dtrans 1093 1094 self.GetNext().SetPrev(self) 1095 self.parent.ellipsepage.ellipse = self.ellipse 1096 self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[ 1097 self.ellipse][1] 1098 1099 def OnEnterPage(self, event): 1100 self.parent.datum_trans = None 1101 if event.GetDirection(): 1102 if len(self.datum) == 0: 1103 # disable 'next' button by default when entering from previous 1104 # page 1105 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 1106 else: 1107 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 1108 1109 event.Skip() 1110 1111 def OnDText(self, event): 1112 """Datum code changed""" 1113 self.datum = event.GetString() 1114 1115 nextButton = wx.FindWindowById(wx.ID_FORWARD) 1116 if len(self.datum) == 0 or self.datum not in self.parent.datums: 1117 nextButton.Enable(False) 1118 else: 1119 self.ellipse = self.parent.datums[self.datum][0] 1120 self.datumdesc = self.parent.datums[self.datum][1] 1121 self.datumparams = self.parent.datums[self.datum][2] 1122 try: 1123 self.datumparams.remove('dx=0.0') 1124 except: 1125 pass 1126 try: 1127 self.datumparams.remove('dy=0.0') 1128 except: 1129 pass 1130 try: 1131 self.datumparams.remove('dz=0.0') 1132 except: 1133 pass 1134 1135 nextButton.Enable(True) 1136 1137 self.Update() 1138 event.Skip() 1139 1140 def OnDSearch(self, event): 1141 """Search geodetic datum by desc""" 1142 search_str = self.searchb.GetValue() 1143 try: 1144 self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search( 1145 index=[ 1146 0, 1147 1, 1148 2], 1149 pattern=search_str) 1150 except: 1151 self.datum = self.datumdesc = self.ellipsoid = '' 1152 1153 event.Skip() 1154 1155 def OnSearchCancel(self, event): 1156 self.datumlist.Search(index=None, pattern="") 1157 event.Skip() 1158 1159 def OnDatumSelected(self, event): 1160 """Datum selected""" 1161 index = event.GetIndex() 1162 item = event.GetItem() 1163 1164 self.datum = self.datumlist.GetItem(index, 0).GetText() 1165 self.tdatum.SetValue(self.datum) 1166 1167 event.Skip() 1168 1169 1170class EllipsePage(TitledPage): 1171 """Wizard page for selecting ellipsoid (select coordinate system option)""" 1172 1173 def __init__(self, wizard, parent): 1174 TitledPage.__init__(self, wizard, _("Specify ellipsoid")) 1175 1176 self.parent = parent 1177 1178 self.ellipse = '' 1179 self.ellipsedesc = '' 1180 self.ellipseparams = '' 1181 self.proj4params = '' 1182 1183 # text input 1184 self.tellipse = self.MakeTextCtrl("", size=(200, -1)) 1185 1186 # search box 1187 self.searchb = SearchCtrl(self, size=(200, -1), 1188 style=wx.TE_PROCESS_ENTER) 1189 self.searchb.ShowCancelButton(True) 1190 # radio buttons 1191 self.radio1 = wx.RadioButton(parent=self, id=wx.ID_ANY, 1192 label=_("Earth based"), 1193 style=wx.RB_GROUP) 1194 self.radioEpsg = wx.RadioButton(parent=self, id=wx.ID_ANY, 1195 label=_("Planetary bodies")) 1196 1197 # create list control for ellipse list 1198 data = [] 1199 # extract code, desc 1200 for key in self.parent.ellipsoids.keys(): 1201 data.append([key, self.parent.ellipsoids[key][0]]) 1202 1203 self.ellipselist = ItemList(self, data=data, 1204 columns=[_('Code'), _('Description')]) 1205 self.ellipselist.resizeLastColumn(30) 1206 1207 # layout 1208 1209 self.sizer.Add(self.MakeLabel(_("Ellipsoid code:")), 1210 flag=wx.ALIGN_RIGHT | 1211 wx.ALIGN_CENTER_VERTICAL | 1212 wx.ALL, border=5, pos=(1, 1)) 1213 self.sizer.Add(self.tellipse, 1214 flag=wx.ALIGN_LEFT | 1215 wx.ALIGN_CENTER_VERTICAL | 1216 wx.ALL, border=5, pos=(1, 2)) 1217 self.sizer.Add(self.radio1, 1218 flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 1219 border=25, pos=(1, 3)) 1220 1221 self.sizer.Add(self.MakeLabel(_("Search in description:")), 1222 flag=wx.ALIGN_RIGHT | 1223 wx.ALIGN_CENTER_VERTICAL | 1224 wx.ALL, border=5, pos=(2, 1)) 1225 self.sizer.Add(self.searchb, 1226 flag=wx.ALIGN_LEFT | 1227 wx.ALIGN_CENTER_VERTICAL | 1228 wx.ALL, border=5, pos=(2, 2)) 1229 self.sizer.Add(self.radioEpsg, 1230 flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 1231 border=25, pos=(2, 3)) 1232 1233 self.sizer.Add(self.ellipselist, 1234 flag=wx.EXPAND | 1235 wx.ALIGN_LEFT | 1236 wx.ALL, border=5, pos=(3, 1), span=(1, 4)) 1237 self.sizer.AddGrowableCol(4) 1238 self.sizer.AddGrowableRow(3) 1239 1240 # events 1241 self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) 1242 self.tellipse.Bind(wx.EVT_TEXT, self.OnText) 1243 self.searchb.Bind(wx.EVT_TEXT, self.OnSearch) 1244 self.searchb.Bind(search_cancel_evt, self.OnSearchCancel) 1245 1246 self.radio1.Bind( 1247 wx.EVT_RADIOBUTTON, 1248 self.SetVal, 1249 id=self.radio1.GetId()) 1250 self.radioEpsg.Bind( 1251 wx.EVT_RADIOBUTTON, 1252 self.SetVal, 1253 id=self.radioEpsg.GetId()) 1254 1255 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 1256 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 1257 1258 def OnEnterPage(self, event): 1259 if len(self.ellipse) == 0: 1260 # disable 'next' button by default 1261 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 1262 else: 1263 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 1264 self.scope = 'earth' 1265 event.Skip() 1266 1267 def OnPageChanging(self, event): 1268 if event.GetDirection() \ 1269 and self.ellipse not in self.parent.ellipsoids \ 1270 and self.ellipse not in self.parent.planetary_ellipsoids: 1271 event.Veto() 1272 1273 # print self.ellipse, self.ellipsedesc, self.ellipseparams 1274 1275 self.proj4params = '' 1276 self.GetNext().SetPrev(self) 1277 self.parent.datumpage.datumparams = '' 1278 # self.GetNext().SetPrev(self) (???) 1279 1280 # FIXME: index number doesn't translate when you've given a valid name 1281 # from the other list 1282 def OnText(self, event): 1283 """Ellipspoid code changed""" 1284 self.ellipse = event.GetString() 1285 nextButton = wx.FindWindowById(wx.ID_FORWARD) 1286 if len(self.ellipse) == 0 or \ 1287 (self.ellipse not in self.parent.ellipsoids and 1288 self.ellipse not in self.parent.planetary_ellipsoids): 1289 nextButton.Enable(False) 1290 self.ellipsedesc = '' 1291 self.ellipseparams = '' 1292 self.proj4params = '' 1293 elif self.ellipse in self.parent.ellipsoids: 1294 self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0] 1295 self.ellipseparams = self.parent.ellipsoids[self.ellipse][1] 1296 nextButton.Enable(True) 1297 elif self.ellipse in self.parent.planetary_ellipsoids: 1298 self.ellipsedesc = self.parent.planetary_ellipsoids[ 1299 self.ellipse][0] 1300 self.ellipseparams = self.parent.planetary_ellipsoids[ 1301 self.ellipse][1] 1302 nextButton.Enable(True) 1303 # print self.ellipse, self.ellipsedesc, self.ellipseparams 1304 1305 def OnSearch(self, event): 1306 """Search ellipsoid by desc""" 1307 try: 1308 self.ellipse, self.ellipsedesc = self.ellipselist.Search( 1309 index=[0, 1], pattern=event.GetString()) 1310 if self.scope == 'earth': 1311 self.ellipseparams = self.parent.ellipsoids[self.ellipse][1] 1312 else: 1313 self.ellipseparams = self.parent.planetary_ellipsoids[ 1314 self.ellipse][1] 1315 except: 1316 self.ellipse = self.ellipsedesc = self.ellipseparams = '' 1317 1318 event.Skip() 1319 1320 def OnSearchCancel(self, event): 1321 self.ellipselist.Search(index=None, pattern="") 1322 event.Skip() 1323 1324 def OnItemSelected(self, event): 1325 """Ellipsoid selected""" 1326 index = event.GetIndex() 1327 item = event.GetItem() 1328 1329 self.ellipse = self.ellipselist.GetItem(index, 0).GetText() 1330 self.tellipse.SetValue(self.ellipse) 1331 1332 event.Skip() 1333 1334 def SetVal(self, event): 1335 """Choose table to use""" 1336 self.ellipselist.DeleteAllItems() 1337 data = [] 1338 if event.GetId() == self.radio1.GetId(): 1339 self.scope = 'earth' 1340 for key in self.parent.ellipsoids.keys(): 1341 data.append([key, self.parent.ellipsoids[key][0]]) 1342 elif event.GetId() == self.radioEpsg.GetId(): 1343 self.scope = 'planetary' 1344 for key in self.parent.planetary_ellipsoids.keys(): 1345 data.append([key, self.parent.planetary_ellipsoids[key][0]]) 1346 1347 self.ellipselist.Populate(data=data, update=True) 1348 1349 1350class GeoreferencedFilePage(TitledPage): 1351 """Wizard page for selecting georeferenced file to use 1352 for setting coordinate system parameters""" 1353 1354 def __init__(self, wizard, parent): 1355 TitledPage.__init__(self, wizard, _("Select georeferenced file")) 1356 1357 self.georeffile = '' 1358 1359 # create controls 1360 self.lfile = self.MakeLabel(_("Georeferenced file:")) 1361 self.tfile = self.MakeTextCtrl(size=(300, -1)) 1362 self.bbrowse = self.MakeButton(_("Browse")) 1363 1364 # do layout 1365 self.sizer.Add(self.lfile, flag=wx.ALIGN_LEFT | 1366 wx.ALIGN_CENTRE_VERTICAL | 1367 wx.ALL, border=5, pos=(1, 1)) 1368 self.sizer.Add(self.tfile, flag=wx.ALIGN_LEFT | 1369 wx.ALIGN_CENTRE_VERTICAL | 1370 wx.ALL, border=5, pos=(1, 2)) 1371 self.sizer.Add(self.bbrowse, flag=wx.ALIGN_LEFT | 1372 wx.ALL, border=5, pos=(1, 3)) 1373 self.sizer.AddGrowableCol(3) 1374 1375 self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) 1376 self.tfile.Bind(wx.EVT_TEXT, self.OnText) 1377 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 1378 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 1379 1380 # do page layout 1381 # self.DoLayout() 1382 1383 def OnEnterPage(self, event): 1384 if len(self.georeffile) == 0: 1385 # disable 'next' button by default 1386 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 1387 else: 1388 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 1389 1390 event.Skip() 1391 1392 def OnPageChanging(self, event): 1393 if event.GetDirection() and not os.path.isfile(self.georeffile): 1394 event.Veto() 1395 self.GetNext().SetPrev(self) 1396 1397 event.Skip() 1398 1399 def OnText(self, event): 1400 """File changed""" 1401 self.georeffile = event.GetString() 1402 nextButton = wx.FindWindowById(wx.ID_FORWARD) 1403 if len(self.georeffile) > 0 and os.path.isfile(self.georeffile): 1404 if not nextButton.IsEnabled(): 1405 nextButton.Enable(True) 1406 else: 1407 if nextButton.IsEnabled(): 1408 nextButton.Enable(False) 1409 1410 event.Skip() 1411 1412 def OnBrowse(self, event): 1413 """Choose file""" 1414 dlg = wx.FileDialog(self, 1415 _("Select georeferenced file"), 1416 os.getcwd(), "", "*.*", wx.FD_OPEN) 1417 if dlg.ShowModal() == wx.ID_OK: 1418 path = dlg.GetPath() 1419 self.tfile.SetValue(path) 1420 dlg.Destroy() 1421 1422 event.Skip() 1423 1424 1425class WKTPage(TitledPage): 1426 """Wizard page for selecting WKT file to use 1427 for setting coordinate system parameters""" 1428 1429 def __init__(self, wizard, parent): 1430 TitledPage.__init__(self, wizard, _( 1431 "Select Well Known Text (WKT) .prj file")) 1432 1433 self.wktfile = '' 1434 1435 # create controls 1436 self.lfile = self.MakeLabel(_("WKT .prj file:")) 1437 self.tfile = self.MakeTextCtrl(size=(300, -1)) 1438 self.bbrowse = self.MakeButton(_("Browse")) 1439 1440 # do layout 1441 self.sizer.Add(self.lfile, flag=wx.ALIGN_LEFT | 1442 wx.ALIGN_CENTRE_VERTICAL | 1443 wx.ALL, border=5, pos=(1, 1)) 1444 self.sizer.Add(self.tfile, flag=wx.ALIGN_LEFT | 1445 wx.ALIGN_CENTRE_VERTICAL | 1446 wx.ALL, border=5, pos=(1, 2)) 1447 self.sizer.Add(self.bbrowse, flag=wx.ALIGN_LEFT | 1448 wx.ALL, border=5, pos=(1, 3)) 1449 self.sizer.AddGrowableCol(3) 1450 1451 self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) 1452 self.tfile.Bind(wx.EVT_TEXT, self.OnText) 1453 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 1454 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 1455 1456 def OnEnterPage(self, event): 1457 if len(self.wktfile) == 0: 1458 # disable 'next' button by default 1459 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 1460 else: 1461 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 1462 1463 event.Skip() 1464 1465 def OnPageChanging(self, event): 1466 if event.GetDirection() and not os.path.isfile(self.wktfile): 1467 event.Veto() 1468 self.GetNext().SetPrev(self) 1469 1470 event.Skip() 1471 1472 def OnText(self, event): 1473 """File changed""" 1474 self.wktfile = event.GetString() 1475 nextButton = wx.FindWindowById(wx.ID_FORWARD) 1476 if len(self.wktfile) > 0 and os.path.isfile(self.wktfile): 1477 if not nextButton.IsEnabled(): 1478 nextButton.Enable(True) 1479 else: 1480 if nextButton.IsEnabled(): 1481 nextButton.Enable(False) 1482 1483 event.Skip() 1484 1485 def OnBrowse(self, event): 1486 """Choose file""" 1487 dlg = wx.FileDialog( 1488 parent=self, 1489 message=_("Select Well Known Text (WKT) .prj file"), 1490 defaultDir=os.getcwd(), 1491 wildcard="PRJ files (*.prj)|*.prj|Files (*.*)|*.*", 1492 style=wx.FD_OPEN) 1493 1494 if dlg.ShowModal() == wx.ID_OK: 1495 path = dlg.GetPath() 1496 self.tfile.SetValue(path) 1497 dlg.Destroy() 1498 1499 event.Skip() 1500 1501 1502class EPSGPage(TitledPage): 1503 """Wizard page for selecting EPSG code for 1504 setting coordinate system parameters""" 1505 1506 def __init__(self, wizard, parent): 1507 TitledPage.__init__(self, wizard, _("Choose EPSG Code")) 1508 self.parent = parent 1509 self.epsgCodeDict = {} 1510 self.epsgcode = None 1511 self.epsgdesc = '' 1512 self.epsgparams = '' 1513 1514 # labels 1515 self.lfile = self.MakeLabel( 1516 _("Path to the EPSG-codes file:"), 1517 style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) 1518 self.lcode = self.MakeLabel( 1519 _("EPSG code:"), 1520 style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) 1521 # text input 1522 epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg') 1523 self.tfile = self.MakeTextCtrl(text=epsgdir, size=(200, -1), 1524 style=wx.TE_PROCESS_ENTER) 1525 self.tcode = self.MakeTextCtrl(size=(200, -1)) 1526 1527 # buttons 1528 self.bbrowse = self.MakeButton(_("Browse")) 1529 1530 # search box 1531 self.searchb = SearchCtrl(self, size=(200, -1), 1532 style=wx.TE_PROCESS_ENTER) 1533 self.searchb.ShowCancelButton(True) 1534 1535 self.epsglist = ItemList( 1536 self, 1537 data=None, 1538 columns=[ 1539 _('Code'), 1540 _('Description'), 1541 _('Parameters')]) 1542 1543 # layout 1544 self.sizer.Add(self.lfile, 1545 flag=wx.ALIGN_LEFT | 1546 wx.ALIGN_CENTER_VERTICAL | 1547 wx.ALL, border=5, pos=(1, 1), span=(1, 2)) 1548 self.sizer.Add(self.tfile, 1549 flag=wx.ALIGN_LEFT | 1550 wx.ALIGN_CENTER_VERTICAL | 1551 wx.ALL, border=5, pos=(1, 3)) 1552 self.sizer.Add(self.bbrowse, 1553 flag=wx.ALIGN_LEFT | 1554 wx.ALIGN_CENTER_VERTICAL | 1555 wx.ALL, border=5, pos=(1, 4)) 1556 self.sizer.Add(self.lcode, 1557 flag=wx.ALIGN_LEFT | 1558 wx.ALIGN_CENTER_VERTICAL | 1559 wx.ALL, border=5, pos=(2, 1), span=(1, 2)) 1560 self.sizer.Add(self.tcode, 1561 flag=wx.ALIGN_LEFT | 1562 wx.ALIGN_CENTER_VERTICAL | 1563 wx.ALL, border=5, pos=(2, 3)) 1564 self.sizer.Add(self.searchb, 1565 flag=wx.ALIGN_LEFT | 1566 wx.ALIGN_CENTER_VERTICAL | 1567 wx.ALL, border=5, pos=(3, 3)) 1568 1569 self.sizer.Add(self.epsglist, 1570 flag=wx.ALIGN_LEFT | wx.EXPAND, pos=(4, 1), 1571 span=(1, 4)) 1572 self.sizer.AddGrowableCol(3) 1573 self.sizer.AddGrowableRow(4) 1574 1575 # events 1576 self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) 1577 self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes) 1578 self.tcode.Bind(wx.EVT_TEXT, self.OnText) 1579 self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) 1580 self.searchb.Bind(wx.EVT_TEXT, self.OnSearch) 1581 self.searchb.Bind(search_cancel_evt, self.OnSearchCancel) 1582 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 1583 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 1584 1585 def OnEnterPage(self, event): 1586 self.parent.datum_trans = None 1587 if event.GetDirection(): 1588 if not self.epsgcode: 1589 # disable 'next' button by default 1590 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 1591 else: 1592 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 1593 1594 # load default epsg database file 1595 self.OnBrowseCodes(None) 1596 1597 event.Skip() 1598 1599 def OnPageChanging(self, event): 1600 if event.GetDirection(): 1601 if not self.epsgcode: 1602 event.Veto() 1603 return 1604 else: 1605 # check for datum transforms 1606 ret = RunCommand('g.proj', 1607 read=True, 1608 epsg=self.epsgcode, 1609 datum_trans='-1', 1610 flags='t') 1611 1612 if ret != '': 1613 dtrans = '' 1614 # open a dialog to select datum transform number 1615 dlg = SelectTransformDialog( 1616 self.parent.parent, transforms=ret) 1617 1618 if dlg.ShowModal() == wx.ID_OK: 1619 dtrans = dlg.GetTransform() 1620 if dtrans == '': 1621 dlg.Destroy() 1622 event.Veto() 1623 return 'Datum transform is required.' 1624 else: 1625 dlg.Destroy() 1626 event.Veto() 1627 return 'Datum transform is required.' 1628 1629 self.parent.datum_trans = dtrans 1630 self.GetNext().SetPrev(self) 1631 1632 def OnText(self, event): 1633 self.epsgcode = event.GetString() 1634 try: 1635 self.epsgcode = int(self.epsgcode) 1636 except: 1637 self.epsgcode = None 1638 1639 nextButton = wx.FindWindowById(wx.ID_FORWARD) 1640 1641 if self.epsgcode and self.epsgCodeDict and \ 1642 self.epsgcode in self.epsgCodeDict.keys(): 1643 self.epsgdesc = self.epsgCodeDict[self.epsgcode][0] 1644 self.epsgparams = self.epsgCodeDict[self.epsgcode][1] 1645 if not nextButton.IsEnabled(): 1646 nextButton.Enable(True) 1647 else: 1648 self.epsgcode = None # not found 1649 if nextButton.IsEnabled(): 1650 nextButton.Enable(False) 1651 self.epsgdesc = self.epsgparams = '' 1652 1653 def OnSearch(self, event): 1654 value = self.searchb.GetValue() 1655 1656 if value == '': 1657 self.epsgcode = None 1658 self.epsgdesc = self.epsgparams = '' 1659 self.tcode.ChangeValue('') 1660 self.searchb.ChangeValue('') 1661 self.OnBrowseCodes(None) 1662 else: 1663 try: 1664 self.epsgcode, self.epsgdesc, self.epsgparams = \ 1665 self.epsglist.Search(index=[0, 1, 2], pattern=value) 1666 except (IndexError, ValueError): # -> no item found 1667 self.epsgcode = None 1668 self.epsgdesc = self.epsgparams = '' 1669 self.tcode.ChangeValue('') 1670 1671 event.Skip() 1672 1673 def OnSearchCancel(self, event): 1674 self.epsglist.Search(index=None, pattern="") 1675 event.Skip() 1676 1677 def OnBrowse(self, event): 1678 """Define path for EPSG code file""" 1679 path = os.path.dirname(self.tfile.GetValue()) 1680 if not path: 1681 path = os.getcwd() 1682 1683 dlg = wx.FileDialog( 1684 parent=self, 1685 message=_("Choose EPSG codes file"), 1686 defaultDir=path, 1687 defaultFile="", 1688 wildcard="*", 1689 style=wx.FD_OPEN) 1690 1691 if dlg.ShowModal() == wx.ID_OK: 1692 path = dlg.GetPath() 1693 self.tfile.SetValue(path) 1694 self.OnBrowseCodes(None) 1695 1696 dlg.Destroy() 1697 1698 event.Skip() 1699 1700 def OnItemSelected(self, event): 1701 """EPSG code selected from the list""" 1702 index = event.GetIndex() 1703 item = event.GetItem() 1704 1705 self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText()) 1706 self.epsgdesc = self.epsglist.GetItem(index, 1).GetText() 1707 self.tcode.SetValue(str(self.epsgcode)) 1708 1709 event.Skip() 1710 1711 def OnBrowseCodes(self, event, search=None): 1712 """Browse EPSG codes""" 1713 try: 1714 self.epsgCodeDict = utils.ReadEpsgCodes() 1715 except OpenError as e: 1716 GError( 1717 parent=self, 1718 message=_("Unable to read EPGS codes: {0}").format(e), 1719 showTraceback=False) 1720 self.epsglist.Populate(list(), update=True) 1721 return 1722 1723 data = list() 1724 for code, val in six.iteritems(self.epsgCodeDict): 1725 if code is not None: 1726 data.append((code, val[0], val[1])) 1727 1728 self.epsglist.Populate(data, update=True) 1729 1730 1731class IAUPage(TitledPage): 1732 """Wizard page for selecting IAU code/WKT for 1733 setting coordinate system parameters""" 1734 1735 def __init__(self, wizard, parent): 1736 TitledPage.__init__(self, wizard, _("Choose IAU Code")) 1737 self.parent = parent 1738 self.epsgCodeDict = {} 1739 self.epsgcode = None 1740 self.epsgdesc = '' 1741 self.epsgparams = '' 1742 1743 # labels 1744 self.lfile = self.MakeLabel( 1745 _("Path to the IAU-codes file:"), 1746 style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) 1747 self.lcode = self.MakeLabel( 1748 _("IAU code:"), 1749 style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) 1750 # text input 1751 epsgdir = utils.PathJoin( 1752 globalvar.ETCDIR, 1753 "proj", 1754 "ogr_csv", 1755 'iau2009.csv') 1756 self.tfile = self.MakeTextCtrl(text=epsgdir, size=(200, -1), 1757 style=wx.TE_PROCESS_ENTER) 1758 self.tcode = self.MakeTextCtrl(size=(200, -1)) 1759 1760 # buttons 1761 self.bbrowse = self.MakeButton(_("Browse")) 1762 1763 # search box 1764 self.searchb = SearchCtrl(self, size=(200, -1), 1765 style=wx.TE_PROCESS_ENTER) 1766 self.searchb.ShowCancelButton(True) 1767 1768 self.epsglist = ItemList( 1769 self, 1770 data=None, 1771 columns=[ 1772 _('Code'), 1773 _('Description'), 1774 _('Parameters')]) 1775 1776 # layout 1777 self.sizer.Add(self.lfile, 1778 flag=wx.ALIGN_LEFT | 1779 wx.ALIGN_CENTER_VERTICAL | 1780 wx.ALL, border=5, pos=(1, 1), span=(1, 2)) 1781 self.sizer.Add(self.tfile, 1782 flag=wx.ALIGN_LEFT | 1783 wx.ALIGN_CENTER_VERTICAL | 1784 wx.ALL, border=5, pos=(1, 3)) 1785 self.sizer.Add(self.bbrowse, 1786 flag=wx.ALIGN_LEFT | 1787 wx.ALIGN_CENTER_VERTICAL | 1788 wx.ALL, border=5, pos=(1, 4)) 1789 self.sizer.Add(self.lcode, 1790 flag=wx.ALIGN_LEFT | 1791 wx.ALIGN_CENTER_VERTICAL | 1792 wx.ALL, border=5, pos=(2, 1), span=(1, 2)) 1793 self.sizer.Add(self.tcode, 1794 flag=wx.ALIGN_LEFT | 1795 wx.ALIGN_CENTER_VERTICAL | 1796 wx.ALL, border=5, pos=(2, 3)) 1797 self.sizer.Add(self.searchb, 1798 flag=wx.ALIGN_LEFT | 1799 wx.ALIGN_CENTER_VERTICAL | 1800 wx.ALL, border=5, pos=(3, 3)) 1801 1802 self.sizer.Add(self.epsglist, 1803 flag=wx.ALIGN_LEFT | wx.EXPAND, pos=(4, 1), 1804 span=(1, 4)) 1805 self.sizer.AddGrowableCol(3) 1806 self.sizer.AddGrowableRow(4) 1807 1808 # events 1809 self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) 1810 self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes) 1811 self.tcode.Bind(wx.EVT_TEXT, self.OnText) 1812 self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) 1813 self.searchb.Bind(wx.EVT_TEXT, self.OnSearch) 1814 self.searchb.Bind(search_cancel_evt, self.OnSearchCancel) 1815 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 1816 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 1817 1818 def OnEnterPage(self, event): 1819 self.parent.datum_trans = None 1820 if event.GetDirection(): 1821 if not self.epsgcode: 1822 # disable 'next' button by default 1823 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 1824 else: 1825 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 1826 1827 # load default epsg database file 1828 self.OnBrowseCodes(None) 1829 1830 event.Skip() 1831 1832 def OnPageChanging(self, event): 1833 if event.GetDirection(): 1834 if not self.epsgcode: 1835 event.Veto() 1836 return 1837 else: 1838 # check for datum transforms 1839 ret = RunCommand('g.proj', 1840 read=True, 1841 proj4=self.epsgparams, 1842 datum_trans='-1', 1843 flags='t') 1844 1845 if ret != '': 1846 dtrans = '' 1847 # open a dialog to select datum transform number 1848 dlg = SelectTransformDialog( 1849 self.parent.parent, transforms=ret) 1850 1851 if dlg.ShowModal() == wx.ID_OK: 1852 dtrans = dlg.GetTransform() 1853 if dtrans == '': 1854 dlg.Destroy() 1855 event.Veto() 1856 return 'Datum transform is required.' 1857 else: 1858 dlg.Destroy() 1859 event.Veto() 1860 return 'Datum transform is required.' 1861 1862 self.parent.datum_trans = dtrans 1863 self.parent.epsgcode = self.epsgcode 1864 self.parent.epsgdesc = self.epsgdesc 1865 1866 # prepare +nadgrids or +towgs84 terms for Summary page. first 1867 # convert them: 1868 ret, projlabel, err = RunCommand( 1869 'g.proj', flags='jft', proj4=self.epsgparams, 1870 datum_trans=self.parent.datum_trans, getErrorMsg=True, 1871 read=True) 1872 # splitting on space alone would break for grid files with 1873 # space in pathname 1874 for projterm in projlabel.split(' +'): 1875 if projterm.find( 1876 "towgs84=") != -1 or projterm.find("nadgrids=") != -1: 1877 self.custom_dtrans_string = ' +%s' % projterm 1878 break 1879 1880 self.GetNext().SetPrev(self) 1881 1882 def OnText(self, event): 1883 self.epsgcode = event.GetString() 1884 try: 1885 self.epsgcode = int(self.epsgcode) 1886 except: 1887 self.epsgcode = None 1888 1889 nextButton = wx.FindWindowById(wx.ID_FORWARD) 1890 1891 # if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys(): 1892 if self.epsgcode: 1893 self.epsgdesc = self.epsgCodeDict[self.epsgcode][0] 1894 self.epsgparams = self.epsgCodeDict[self.epsgcode][1] 1895 if not nextButton.IsEnabled(): 1896 nextButton.Enable(True) 1897 else: 1898 self.epsgcode = None # not found 1899 if nextButton.IsEnabled(): 1900 nextButton.Enable(False) 1901 self.epsgdesc = self.epsgparams = '' 1902 1903 def OnSearch(self, event): 1904 value = self.searchb.GetValue() 1905 1906 if value == '': 1907 self.epsgcode = None 1908 self.epsgdesc = self.epsgparams = '' 1909 self.tcode.SetValue('') 1910 self.searchb.SetValue('') 1911 self.OnBrowseCodes(None) 1912 else: 1913 try: 1914 self.epsgcode, self.epsgdesc, self.epsgparams = \ 1915 self.epsglist.Search(index=[0, 1, 2], pattern=value) 1916 except (IndexError, ValueError): # -> no item found 1917 self.epsgcode = None 1918 self.epsgdesc = self.epsgparams = '' 1919 self.tcode.SetValue('') 1920 1921 event.Skip() 1922 1923 def OnSearchCancel(self, event): 1924 self.epsglist.Search(index=None, pattern="") 1925 event.Skip() 1926 1927 def OnBrowse(self, event): 1928 """Define path for IAU code file""" 1929 path = os.path.dirname(self.tfile.GetValue()) 1930 if not path: 1931 path = os.getcwd() 1932 1933 dlg = wx.FileDialog( 1934 parent=self, 1935 message=_("Choose IAU codes file"), 1936 defaultDir=path, 1937 defaultFile="", 1938 wildcard="*", 1939 style=wx.FD_OPEN) 1940 1941 if dlg.ShowModal() == wx.ID_OK: 1942 path = dlg.GetPath() 1943 self.tfile.SetValue(path) 1944 self.OnBrowseCodes(None) 1945 1946 dlg.Destroy() 1947 1948 event.Skip() 1949 1950 def OnItemSelected(self, event): 1951 """IAU code selected from the list""" 1952 index = event.GetIndex() 1953 item = event.GetItem() 1954 1955 self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText()) 1956 # This is here that the index 2 (aka WKT) should be loaded in a 1957 # variable 1958 self.epsgdesc = self.epsglist.GetItem(index, 1).GetText() 1959 self.tcode.SetValue(str(self.epsgcode)) 1960 1961 event.Skip() 1962 1963 def OnBrowseCodes(self, event, search=None): 1964 """Browse IAU codes""" 1965 try: 1966 self.epsgCodeDict = utils.ReadEpsgCodes() 1967 except OpenError as e: 1968 GError( 1969 parent=self, 1970 message=_("Unable to read IAU codes: {0}").format(e), 1971 showTraceback=False) 1972 self.epsglist.Populate(list(), update=True) 1973 return 1974 1975 data = list() 1976 for code, val in six.iteritems(self.epsgCodeDict): 1977 if code is not None: 1978 data.append((code, val[0], val[1])) 1979 1980 self.epsglist.Populate(data, update=True) 1981 1982 1983class CustomPage(TitledPage): 1984 """Wizard page for entering custom PROJ.4 string 1985 for setting coordinate system parameters""" 1986 1987 def __init__(self, wizard, parent): 1988 TitledPage.__init__( 1989 self, wizard, 1990 _("Choose method of specifying georeferencing parameters")) 1991 global coordsys 1992 self.customstring = '' 1993 self.parent = parent 1994 1995 # widgets 1996 self.text_proj4string = self.MakeTextCtrl(size=(400, 200), 1997 style=wx.TE_MULTILINE) 1998 self.label_proj4string = self.MakeLabel( 1999 _("Enter PROJ.4 parameters string:")) 2000 2001 # layout 2002 self.sizer.Add(self.label_proj4string, 2003 flag=wx.ALIGN_LEFT | wx.ALL, 2004 border=5, pos=(1, 1)) 2005 self.sizer.Add(self.text_proj4string, 2006 flag=wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 2007 border=5, pos=(2, 1), span=(1, 2)) 2008 self.sizer.AddGrowableRow(2) 2009 self.sizer.AddGrowableCol(2) 2010 2011 self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring) 2012 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging) 2013 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 2014 2015 def OnEnterPage(self, event): 2016 if len(self.customstring) == 0: 2017 # disable 'next' button by default 2018 wx.FindWindowById(wx.ID_FORWARD).Enable(False) 2019 else: 2020 wx.FindWindowById(wx.ID_FORWARD).Enable(True) 2021 2022 def OnPageChanging(self, event): 2023 if event.GetDirection(): 2024 self.custom_dtrans_string = '' 2025 2026 if self.customstring.find('+datum=') < 0: 2027 self.GetNext().SetPrev(self) 2028 return 2029 2030 # check for datum tranforms 2031 # FIXME: -t flag is a hack-around for trac bug #1849 2032 ret, out, err = RunCommand('g.proj', 2033 read=True, getErrorMsg=True, 2034 proj4=self.customstring, 2035 datum_trans='-1', 2036 flags='t') 2037 if ret != 0: 2038 wx.MessageBox(parent=self, 2039 message=err, 2040 caption=_("Error"), 2041 style=wx.OK | wx.ICON_ERROR | wx.CENTRE) 2042 event.Veto() 2043 return 2044 2045 if out: 2046 dtrans = '' 2047 # open a dialog to select datum transform number 2048 dlg = SelectTransformDialog(self.parent.parent, transforms=out) 2049 2050 if dlg.ShowModal() == wx.ID_OK: 2051 dtrans = dlg.GetTransform() 2052 if dtrans == '': 2053 dlg.Destroy() 2054 event.Veto() 2055 return _('Datum transform is required.') 2056 else: 2057 dlg.Destroy() 2058 event.Veto() 2059 return _('Datum transform is required.') 2060 2061 self.parent.datum_trans = dtrans 2062 2063 # prepare +nadgrids or +towgs84 terms for Summary page. first 2064 # convert them: 2065 ret, projlabel, err = RunCommand('g.proj', 2066 flags='jft', 2067 proj4=self.customstring, 2068 datum_trans=dtrans, 2069 getErrorMsg=True, 2070 read=True) 2071 # splitting on space alone would break for grid files with 2072 # space in pathname 2073 for projterm in projlabel.split(' +'): 2074 if projterm.find( 2075 "towgs84=") != -1 or projterm.find("nadgrids=") != -1: 2076 self.custom_dtrans_string = ' +%s' % projterm 2077 break 2078 2079 self.GetNext().SetPrev(self) 2080 2081 def GetProjstring(self, event): 2082 """Change proj string""" 2083 # TODO: check PROJ.4 syntax 2084 self.customstring = event.GetString() 2085 nextButton = wx.FindWindowById(wx.ID_FORWARD) 2086 if len(self.customstring) == 0: 2087 if nextButton.IsEnabled(): 2088 nextButton.Enable(False) 2089 else: 2090 if not nextButton.IsEnabled(): 2091 nextButton.Enable() 2092 2093 2094class SummaryPage(TitledPage): 2095 """Shows summary result of choosing coordinate system parameters 2096 prior to creating location""" 2097 2098 def __init__(self, wizard, parent): 2099 TitledPage.__init__(self, wizard, _("Summary")) 2100 self.parent = parent 2101 2102 self.panelTitle = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY) 2103 self.panelProj4string = scrolled.ScrolledPanel( 2104 parent=self, id=wx.ID_ANY) 2105 self.panelProj = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY) 2106 2107 # labels 2108 self.ldatabase = self.MakeLabel() 2109 self.llocation = self.MakeLabel() 2110 self.llocTitle = self.MakeLabel(parent=self.panelTitle) 2111 self.lprojection = self.MakeLabel(parent=self.panelProj) 2112 self.lproj4string = self.MakeLabel(parent=self.panelProj4string) 2113 2114 self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) 2115 2116 # do sub-page layout 2117 self._doLayout() 2118 2119 def _doLayout(self): 2120 """Do page layout""" 2121 2122 titleSizer = wx.BoxSizer(wx.VERTICAL) 2123 titleSizer.Add(self.llocTitle, proportion=1, 2124 flag=wx.EXPAND | wx.ALL, border=5) 2125 self.panelTitle.SetSizer(titleSizer) 2126 2127 projSizer = wx.BoxSizer(wx.VERTICAL) 2128 projSizer.Add(self.lprojection, proportion=1, 2129 flag=wx.EXPAND | wx.ALL, border=5) 2130 self.panelProj.SetSizer(projSizer) 2131 2132 proj4stringSizer = wx.BoxSizer(wx.VERTICAL) 2133 proj4stringSizer.Add(self.lproj4string, proportion=1, 2134 flag=wx.EXPAND | wx.ALL, border=5) 2135 self.panelProj4string.SetSizer(proj4stringSizer) 2136 2137 self.panelProj4string.SetupScrolling() 2138 self.panelProj.SetupScrolling(scroll_y=False) 2139 self.panelTitle.SetupScrolling(scroll_y=False) 2140 2141 self.sizer.Add(self.MakeLabel(_("GRASS Database:")), 2142 flag=wx.ALIGN_LEFT | wx.ALL, 2143 border=5, pos=(1, 0)) 2144 self.sizer.Add(self.ldatabase, 2145 flag=wx.ALIGN_LEFT | wx.ALL, 2146 border=5, pos=(1, 1)) 2147 self.sizer.Add(self.MakeLabel(_("Location Name:")), 2148 flag=wx.ALIGN_LEFT | wx.ALL, 2149 border=5, pos=(2, 0)) 2150 self.sizer.Add(self.llocation, 2151 flag=wx.ALIGN_LEFT | wx.ALL, 2152 border=5, pos=(2, 1)) 2153 self.sizer.Add(self.MakeLabel(_("Location Title:")), 2154 flag=wx.ALIGN_LEFT | wx.ALL, 2155 border=5, pos=(3, 0)) 2156 self.sizer.Add(self.panelTitle, 2157 flag=wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 2158 border=0, pos=(3, 1)) 2159 self.sizer.Add(self.MakeLabel(_("Projection:")), 2160 flag=wx.ALIGN_LEFT | wx.ALL, 2161 border=5, pos=(4, 0)) 2162 self.sizer.Add(self.panelProj, 2163 flag=wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 2164 border=0, pos=(4, 1)) 2165 self.sizer.Add( 2166 self.MakeLabel( 2167 _("PROJ.4 definition:\n (non-definitive)")), 2168 flag=wx.ALIGN_LEFT | wx.ALL, 2169 border=5, 2170 pos=( 2171 5, 2172 0)) 2173 self.sizer.Add(self.panelProj4string, 2174 flag=wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 2175 border=0, pos=(5, 1)) 2176 self.sizer.AddGrowableCol(1) 2177 self.sizer.AddGrowableRow(3, 1) 2178 self.sizer.AddGrowableRow(4, 1) 2179 self.sizer.AddGrowableRow(5, 5) 2180 2181 def OnEnterPage(self, event): 2182 """Insert values into text controls for summary of location 2183 creation options 2184 """ 2185 database = self.parent.startpage.grassdatabase 2186 location = self.parent.startpage.location 2187 proj4string = self.parent.CreateProj4String() 2188 iauproj4string = self.parent.iaupage.epsgparams 2189 epsgcode = self.parent.epsgpage.epsgcode 2190 datum = self.parent.datumpage.datum 2191 dtrans = self.parent.datum_trans 2192 global coordsys 2193 2194 # print coordsys,proj4string 2195 if coordsys in ('proj', 'epsg', 'iau', 'wkt', 'file'): 2196 extra_opts = {} 2197 extra_opts['location'] = 'location' 2198 extra_opts['getErrorMsg'] = True 2199 extra_opts['read'] = True 2200 2201 if coordsys == 'proj': 2202 addl_opts = {} 2203 if len(datum) > 0: 2204 extra_opts['datum'] = '%s' % datum 2205 extra_opts['datum_trans'] = dtrans 2206 2207 ret, projlabel, err = RunCommand('g.proj', 2208 flags='jf', 2209 proj4=proj4string, 2210 **extra_opts) 2211 elif coordsys == 'iau': 2212 addl_opts = {} 2213 if len(datum) > 0: 2214 extra_opts['datum'] = '%s' % datum 2215 extra_opts['datum_trans'] = dtrans 2216 2217 ret, projlabel, err = RunCommand('g.proj', 2218 flags='jf', 2219 proj4=iauproj4string, 2220 **extra_opts) 2221 elif coordsys == 'epsg': 2222 ret, projlabel, err = RunCommand('g.proj', 2223 flags='jft', 2224 epsg=epsgcode, 2225 datum_trans=dtrans, 2226 **extra_opts) 2227 elif coordsys == 'file': 2228 ret, projlabel, err = RunCommand( 2229 'g.proj', flags='jft', 2230 georef=self.parent.filepage.georeffile, **extra_opts) 2231 elif coordsys == 'wkt': 2232 ret, projlabel, err = RunCommand( 2233 'g.proj', flags='jft', wkt=self.parent.wktpage.wktfile, **extra_opts) 2234 2235 finishButton = wx.FindWindowById(wx.ID_FORWARD) 2236 if ret == 0: 2237 if datum != '': 2238 projlabel = projlabel + '+datum=%s' % datum 2239 self.lproj4string.SetLabel( 2240 projlabel.replace(' +', os.linesep + '+')) 2241 finishButton.Enable(True) 2242 else: 2243 GError(err, parent=self) 2244 self.lproj4string.SetLabel('') 2245 finishButton.Enable(False) 2246 2247 projdesc = self.parent.projpage.projdesc 2248 ellipsedesc = self.parent.ellipsepage.ellipsedesc 2249 datumdesc = self.parent.datumpage.datumdesc 2250 # print projdesc,ellipsedesc,datumdesc 2251 self.ldatabase.SetLabel(database) 2252 self.llocation.SetLabel(location) 2253 self.llocTitle.SetLabel(self.parent.startpage.locTitle) 2254 2255 label = '' 2256 if coordsys == 'epsg': 2257 label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, 2258 self.parent.epsgpage.epsgdesc) 2259 elif coordsys == 'iau': 2260 label = 'IAU code %s (%s)' % (self.parent.iaupage.epsgcode, 2261 self.parent.iaupage.epsgdesc) 2262 elif coordsys == 'file': 2263 label = 'matches file %s' % self.parent.filepage.georeffile 2264 2265 elif coordsys == 'wkt': 2266 label = 'matches file %s' % self.parent.wktpage.wktfile 2267 2268 elif coordsys == 'proj': 2269 label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc)) 2270 2271 elif coordsys == 'xy': 2272 label = ('XY coordinate system (not projected).') 2273 self.lproj4string.SetLabel("") 2274 2275 elif coordsys == 'custom': 2276 label = _("custom") 2277 combo_str = self.parent.custompage.customstring + \ 2278 self.parent.custompage.custom_dtrans_string 2279 self.lproj4string.SetLabel( 2280 ('%s' % 2281 combo_str.replace( 2282 ' +', 2283 os.linesep + 2284 '+'))) 2285 2286 self.lprojection.SetLabel(label) 2287 2288 def OnFinish(self, event): 2289 dlg = wx.MessageDialog( 2290 parent=self.wizard, 2291 message=_("Do you want to create GRASS location <%s>?") % 2292 location, 2293 caption=_("Create new location?"), 2294 style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) 2295 2296 if dlg.ShowModal() == wx.ID_NO: 2297 dlg.Destroy() 2298 event.Veto() 2299 else: 2300 dlg.Destroy() 2301 event.Skip() 2302 2303 2304class LocationWizard(wx.Object): 2305 """Start wizard here and finish wizard here 2306 """ 2307 2308 def __init__(self, parent, grassdatabase): 2309 self.__cleanUp() 2310 2311 global coordsys 2312 self.parent = parent 2313 2314 # 2315 # define wizard image 2316 # 2317 imagePath = os.path.join(globalvar.IMGDIR, "loc_wizard_qgis.png") 2318 wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG) 2319 wizbmp = wizbmp.ConvertToBitmap() 2320 2321 # 2322 # get georeferencing information from tables in $GISBASE/etc 2323 # 2324 self.__readData() 2325 2326 # 2327 # datum transform number and list of datum transforms 2328 # 2329 self.datum_trans = None 2330 self.proj4string = '' 2331 2332 # file from which new location is created 2333 self.georeffile = None 2334 2335 # additional settings 2336 self.default_region = False 2337 self.user_mapset = False 2338 2339 # 2340 # define wizard pages 2341 # 2342 self.wizard = WizardWithHelpButton( 2343 parent, 2344 id=wx.ID_ANY, 2345 title=_("Define new GRASS Location"), 2346 bitmap=wizbmp) 2347 self.wizard.Bind(wiz.EVT_WIZARD_HELP, self.OnHelp) 2348 2349 self.startpage = DatabasePage(self.wizard, self, grassdatabase) 2350 self.csystemspage = CoordinateSystemPage(self.wizard, self) 2351 self.projpage = ProjectionsPage(self.wizard, self) 2352 self.datumpage = DatumPage(self.wizard, self) 2353 self.paramspage = ProjParamsPage(self.wizard, self) 2354 self.epsgpage = EPSGPage(self.wizard, self) 2355 self.iaupage = IAUPage(self.wizard, self) 2356 self.filepage = GeoreferencedFilePage(self.wizard, self) 2357 self.wktpage = WKTPage(self.wizard, self) 2358 self.ellipsepage = EllipsePage(self.wizard, self) 2359 self.custompage = CustomPage(self.wizard, self) 2360 self.sumpage = SummaryPage(self.wizard, self) 2361 2362 # 2363 # set the initial order of the pages 2364 # (should follow the epsg line) 2365 # 2366 self.startpage.SetNext(self.csystemspage) 2367 2368 self.csystemspage.SetPrev(self.startpage) 2369 self.csystemspage.SetNext(self.sumpage) 2370 2371 self.projpage.SetPrev(self.csystemspage) 2372 self.projpage.SetNext(self.paramspage) 2373 2374 self.paramspage.SetPrev(self.projpage) 2375 self.paramspage.SetNext(self.datumpage) 2376 2377 self.datumpage.SetPrev(self.paramspage) 2378 self.datumpage.SetNext(self.sumpage) 2379 2380 self.ellipsepage.SetPrev(self.paramspage) 2381 self.ellipsepage.SetNext(self.sumpage) 2382 2383 self.epsgpage.SetPrev(self.csystemspage) 2384 self.epsgpage.SetNext(self.sumpage) 2385 2386 self.iaupage.SetPrev(self.csystemspage) 2387 self.iaupage.SetNext(self.sumpage) 2388 2389 self.filepage.SetPrev(self.csystemspage) 2390 self.filepage.SetNext(self.sumpage) 2391 2392 self.wktpage.SetPrev(self.csystemspage) 2393 self.wktpage.SetNext(self.sumpage) 2394 2395 self.custompage.SetPrev(self.csystemspage) 2396 self.custompage.SetNext(self.sumpage) 2397 2398 self.sumpage.SetPrev(self.csystemspage) 2399 2400 # 2401 # do pages layout 2402 # 2403 self.startpage.DoLayout() 2404 self.csystemspage.DoLayout() 2405 self.projpage.DoLayout() 2406 self.datumpage.DoLayout() 2407 self.paramspage.DoLayout() 2408 self.epsgpage.DoLayout() 2409 self.iaupage.DoLayout() 2410 self.filepage.DoLayout() 2411 self.wktpage.DoLayout() 2412 self.ellipsepage.DoLayout() 2413 self.custompage.DoLayout() 2414 self.sumpage.DoLayout() 2415 self.wizard.FitToPage(self.datumpage) 2416 size = self.wizard.GetPageSize() 2417 self.wizard.SetPageSize((size[0], size[1] + 75)) 2418 2419 # new location created? 2420 self.location = None 2421 success = False 2422 2423 # location created in different GIS database? 2424 self.altdb = False 2425 2426 # 2427 # run wizard... 2428 # 2429 if self.wizard.RunWizard(self.startpage): 2430 msg = self.OnWizFinished() 2431 if not msg: 2432 self.wizard.Destroy() 2433 self.location = self.startpage.location 2434 self.grassdatabase = self.startpage.grassdatabase 2435 self.georeffile = self.filepage.georeffile 2436 self.default_region = self.startpage.tlocRegion.IsChecked() 2437 self.user_mapset = self.startpage.tlocUserMapset.IsChecked() 2438 # FIXME here was code for setting default region, what for is this if: 2439 # if self.altdb == False: 2440 2441 else: # -> error 2442 self.wizard.Destroy() 2443 GError(parent=self.parent, 2444 message="%s" % _("Unable to create new location. " 2445 "Location <%(loc)s> not created.\n\n" 2446 "Details: %(err)s") % 2447 {'loc': self.startpage.location, 2448 'err': msg}) 2449 else: # -> canceled 2450 self.wizard.Destroy() 2451 GMessage(parent=self.parent, 2452 message=_("Location wizard canceled. " 2453 "Location not created.")) 2454 2455 self.__cleanUp() 2456 2457 def __cleanUp(self): 2458 global coordsys 2459 global north 2460 global south 2461 global east 2462 global west 2463 global resolution 2464 global wizerror 2465 global translist 2466 2467 coordsys = None 2468 north = None 2469 south = None 2470 east = None 2471 west = None 2472 resolution = None 2473 transformlist = list() 2474 2475 def __readData(self): 2476 """Get georeferencing information from tables in $GISBASE/etc/proj""" 2477 2478 # read projection and parameters 2479 f = open(os.path.join(globalvar.ETCDIR, "proj", "parms.table"), "r") 2480 self.projections = {} 2481 self.projdesc = {} 2482 for line in f.readlines(): 2483 line = line.strip() 2484 try: 2485 proj, projdesc, params = line.split(':') 2486 paramslist = params.split(';') 2487 plist = [] 2488 for p in paramslist: 2489 if p == '': 2490 continue 2491 p1, pdefault = p.split(',') 2492 pterm, pask = p1.split('=') 2493 p = [pterm.strip(), pask.strip(), pdefault.strip()] 2494 plist.append(p) 2495 self.projections[ 2496 proj.lower().strip()] = ( 2497 projdesc.strip(), plist) 2498 self.projdesc[proj.lower().strip()] = projdesc.strip() 2499 except: 2500 continue 2501 f.close() 2502 2503 # read datum definitions 2504 f = open(os.path.join(globalvar.ETCDIR, "proj", "datum.table"), "r") 2505 self.datums = {} 2506 paramslist = [] 2507 for line in f.readlines(): 2508 line = line.expandtabs(1) 2509 line = line.strip() 2510 if line == '' or line[0] == "#": 2511 continue 2512 datum, info = line.split(" ", 1) 2513 info = info.strip() 2514 datumdesc, params = info.split(" ", 1) 2515 datumdesc = datumdesc.strip('"') 2516 paramlist = params.split() 2517 ellipsoid = paramlist.pop(0) 2518 self.datums[datum] = ( 2519 ellipsoid, datumdesc.replace( 2520 '_', ' '), paramlist) 2521 f.close() 2522 2523 # read Earth-based ellipsiod definitions 2524 f = open(os.path.join(globalvar.ETCDIR, "proj", "ellipse.table"), "r") 2525 self.ellipsoids = {} 2526 for line in f.readlines(): 2527 line = line.expandtabs(1) 2528 line = line.strip() 2529 if line == '' or line[0] == "#": 2530 continue 2531 ellipse, rest = line.split(" ", 1) 2532 rest = rest.strip('" ') 2533 desc, params = rest.split('"', 1) 2534 desc = desc.strip('" ') 2535 paramslist = params.split() 2536 self.ellipsoids[ellipse] = (desc, paramslist) 2537 f.close() 2538 2539 # read Planetary ellipsiod definitions 2540 f = open( 2541 os.path.join( 2542 globalvar.ETCDIR, 2543 "proj", 2544 "ellipse.table.solar.system"), 2545 "r") 2546 self.planetary_ellipsoids = {} 2547 for line in f.readlines(): 2548 line = line.expandtabs(1) 2549 line = line.strip() 2550 if line == '' or line[0] == "#": 2551 continue 2552 ellipse, rest = line.split(" ", 1) 2553 rest = rest.strip('" ') 2554 desc, params = rest.split('"', 1) 2555 desc = desc.strip('" ') 2556 paramslist = params.split() 2557 self.planetary_ellipsoids[ellipse] = (desc, paramslist) 2558 f.close() 2559 2560 # read projection parameter description and parsing table 2561 f = open(os.path.join(globalvar.ETCDIR, "proj", "desc.table"), "r") 2562 self.paramdesc = {} 2563 for line in f.readlines(): 2564 line = line.strip() 2565 try: 2566 pparam, datatype, proj4term, desc = line.split(':') 2567 self.paramdesc[pparam] = (datatype, proj4term, desc) 2568 except: 2569 continue 2570 f.close() 2571 2572 def OnWizFinished(self): 2573 """Wizard finished, create new location 2574 2575 :return: error message on error 2576 :return: None on success 2577 """ 2578 database = self.startpage.grassdatabase 2579 location = self.startpage.location 2580 2581 # location already exists? 2582 if os.path.isdir(os.path.join(database, location)): 2583 GError(parent=self.wizard, 2584 message="%s <%s>: %s" % 2585 (_("Unable to create new location"), 2586 os.path.join(database, location), 2587 _("Location already exists in GRASS Database."))) 2588 return None 2589 2590 # current GISDbase or a new one? 2591 current_gdb = decode(grass.gisenv()['GISDBASE']) 2592 if current_gdb != database: 2593 # change to new GISDbase or create new one 2594 if os.path.isdir(database) != True: 2595 # create new directory 2596 try: 2597 os.mkdir(database) 2598 except OSError as error: 2599 GError(parent=self.wizard, message="%s <%s>" % 2600 (_("Unable to create new GRASS Database"), 2601 database)) 2602 return None 2603 2604 # change to new GISDbase directory 2605 RunCommand('g.gisenv', 2606 parent=self.wizard, 2607 set='GISDBASE=%s' % database) 2608 2609 wx.MessageBox( 2610 parent=self.wizard, 2611 message=_( 2612 "Location <%(loc)s> will be created " 2613 "in GIS data directory <%(dir)s>. " 2614 "You will need to change the default GIS " 2615 "data directory in the GRASS startup screen.") % 2616 {'loc': location, 'dir': database}, 2617 caption=_("New GIS data directory"), 2618 style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE) 2619 2620 # location created in alternate GISDbase 2621 self.altdb = True 2622 2623 global coordsys 2624 try: 2625 if coordsys == "xy": 2626 grass.create_location(dbase=self.startpage.grassdatabase, 2627 location=self.startpage.location, 2628 desc=self.startpage.locTitle) 2629 elif coordsys == "proj": 2630 grass.create_location(dbase=self.startpage.grassdatabase, 2631 location=self.startpage.location, 2632 proj4=self.CreateProj4String(), 2633 datum=self.datumpage.datum, 2634 datum_trans=self.datum_trans, 2635 desc=self.startpage.locTitle) 2636 elif coordsys == 'custom': 2637 addl_opts = {} 2638 if self.datum_trans is not None: 2639 addl_opts['datum_trans'] = self.datum_trans 2640 2641 grass.create_location(dbase=self.startpage.grassdatabase, 2642 location=self.startpage.location, 2643 proj4=self.custompage.customstring, 2644 desc=self.startpage.locTitle, 2645 **addl_opts) 2646 elif coordsys == "epsg": 2647 if not self.epsgpage.epsgcode: 2648 return _('EPSG code missing.') 2649 2650 grass.create_location(dbase=self.startpage.grassdatabase, 2651 location=self.startpage.location, 2652 epsg=self.epsgpage.epsgcode, 2653 datum=self.datumpage.datum, 2654 datum_trans=self.datum_trans, 2655 desc=self.startpage.locTitle) 2656 elif coordsys == "iau": 2657 if not self.iaupage.epsgcode: 2658 return _('IAU code missing.') 2659 2660 grass.create_location(dbase=self.startpage.grassdatabase, 2661 location=self.startpage.location, 2662 proj4=self.iaupage.epsgparams, 2663 datum=self.datumpage.datum, 2664 datum_trans=self.datum_trans, 2665 desc=self.startpage.locTitle) 2666 elif coordsys == "file": 2667 if not self.filepage.georeffile or \ 2668 not os.path.isfile(self.filepage.georeffile): 2669 return _("File <%s> not found." % self.filepage.georeffile) 2670 2671 grass.create_location(dbase=self.startpage.grassdatabase, 2672 location=self.startpage.location, 2673 filename=self.filepage.georeffile, 2674 desc=self.startpage.locTitle) 2675 elif coordsys == "wkt": 2676 if not self.wktpage.wktfile or \ 2677 not os.path.isfile(self.wktpage.wktfile): 2678 return _("File <%s> not found." % self.wktpage.wktfile) 2679 2680 grass.create_location(dbase=self.startpage.grassdatabase, 2681 location=self.startpage.location, 2682 wkt=self.wktpage.wktfile, 2683 desc=self.startpage.locTitle) 2684 2685 except grass.ScriptError as e: 2686 return e.value 2687 2688 return None 2689 2690 def CreateProj4String(self): 2691 """Constract PROJ.4 string""" 2692 location = self.startpage.location 2693 proj = self.projpage.p4proj 2694 projdesc = self.projpage.projdesc 2695 proj4params = self.paramspage.p4projparams 2696 2697# datum = self.datumpage.datum 2698 if self.datumpage.datumdesc: 2699 datumdesc = self.datumpage.datumdesc + ' - ' + self.datumpage.ellipse 2700 else: 2701 datumdesc = '' 2702 datumparams = self.datumpage.datumparams 2703 ellipsedesc = self.ellipsepage.ellipsedesc 2704 ellipseparams = self.ellipsepage.ellipseparams 2705 2706 # 2707 # creating PROJ.4 string 2708 # 2709 proj4string = '%s %s' % (proj, proj4params) 2710 2711 # set ellipsoid parameters 2712 for item in ellipseparams: 2713 if item[:4] == 'f=1/': 2714 item = ' +rf=' + item[4:] 2715 else: 2716 item = ' +' + item 2717 proj4string = '%s %s' % (proj4string, item) 2718 2719 # set datum transform parameters if relevant 2720 if datumparams: 2721 for item in datumparams: 2722 proj4string = '%s +%s' % (proj4string, item) 2723 2724 proj4string = '%s +no_defs' % proj4string 2725 2726 return proj4string 2727 2728 def OnHelp(self, event): 2729 """'Help' button clicked""" 2730 2731 # help text in lib/init/helptext.html 2732 RunCommand('g.manual', entry='helptext') 2733 2734 2735class WizardWithHelpButton(Wizard): 2736 2737 def __init__(self, parent, id, title, bitmap): 2738 if globalvar.wxPythonPhoenix: 2739 Wizard.__init__(self) 2740 self.SetExtraStyle(wx.adv.WIZARD_EX_HELPBUTTON) 2741 self.Create(parent=parent, id=id, title=title, bitmap=bitmap) 2742 else: 2743 pre = wiz.PreWizard() 2744 pre.SetExtraStyle(wx.wizard.WIZARD_EX_HELPBUTTON) 2745 pre.Create(parent=parent, id=id, title=title, bitmap=bitmap) 2746 self.PostCreate(pre) 2747