/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/projdialog.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Thuban/UI/projdialog.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1833 - (show annotations)
Mon Oct 20 11:00:57 2003 UTC (21 years, 4 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 35282 byte(s)
(ProjFrame.write_proj_file): New. helper
method to write a projfile and display a busy cursor and error
dialogs.
(ProjFrame._OnSave, ProjFrame._OnAddToList, ProjFrame._OnImport)
(ProjFrame._OnExport, ProjFrame._OnRemove): Use write_proj_file
(ProjFrame.__FillAvailList): Translate "<None>" too and display a
busy cursor while loading the user and system prj files.

1 # Copyright (c) 2003 by Intevation GmbH
2 # Authors:
3 # Jonathan Coles <[email protected]>
4 # Frank Koormann <[email protected]>
5 # Jan-Oliver Wagner <[email protected]>
6 #
7 # This program is free software under the GPL (>=v2)
8 # Read the file COPYING coming with Thuban for details.
9
10 """Projection dialog"""
11
12 __version__ = "$Revision$"
13 # $Source$
14 # $Id$
15
16 import os
17 from wxPython.wx import *
18
19 from Thuban import _
20
21 from Thuban.Model.proj import Projection, ProjFile
22
23 from Thuban.Model.resource import get_user_proj_file, get_system_proj_file, \
24 read_proj_file, write_proj_file
25 from Thuban.UI.dialogs import NonModalNonParentDialog
26
27 from common import ThubanBeginBusyCursor, ThubanEndBusyCursor
28 from sizers import NotebookLikeSizer
29
30 ID_PROJ_ADVANCED = 4001
31 ID_PROJ_PROJCHOICE = 4002
32 ID_PROJ_ADDTOLIST = 4003
33 ID_PROJ_NEW = 4004
34 ID_PROJ_REVERT = 4006
35 ID_PROJ_AVAIL = 4009
36 ID_PROJ_SAVE = 4010
37 ID_PROJ_IMPORT = 4011
38 ID_PROJ_EXPORT = 4012
39 ID_PROJ_REMOVE = 4013
40 ID_PROJ_PROJNAME = 4014
41
42 CLIENT_PROJ = 0
43 CLIENT_PROJFILE = 1
44
45 class ProjFrame(NonModalNonParentDialog):
46
47 def __init__(self, parent, name, title, receiver):
48 """Initialize the projection dialog.
49
50 receiver -- An object that implements the following methods:
51 SetProjection(projection)
52 GetProjection()
53 """
54 NonModalNonParentDialog.__init__(self, parent, name, title)
55
56 self.projection_panel_defs = [
57 ("tmerc", _("Transverse Mercator"), TMPanel),
58 ("utm", _("Universal Transverse Mercator"), UTMPanel),
59 ("lcc", _("Lambert Conic Conformal"), LCCPanel),
60 ("latlong", _("Geographic"), GeoPanel)]
61 self.receiver = receiver
62 self.haveTried = False
63 self.curProjPanel = None
64
65 self.build_dialog()
66 self.Layout()
67
68 self.originalProjection = self.receiver.GetProjection()
69
70 self.__DoOnProjAvail()
71 self.button_ok.SetFocus()
72 self.availprojs.SetFocus()
73
74 def build_dialog(self):
75 """Build the dialog's widgets and set the event handlers"""
76 self.topBox = top_box = wxBoxSizer(wxVERTICAL)
77
78 main_box = wxBoxSizer(wxHORIZONTAL)
79 top_box.Add(main_box, 1, wxALL|wxEXPAND)
80
81 #
82 # The projection list and associated controls
83 #
84 vbox = wxBoxSizer(wxVERTICAL)
85 main_box.Add(vbox, 0, wxALL|wxEXPAND)
86
87 label = wxStaticText(self, -1, _("Available Projections:"))
88 vbox.Add(label, 0, wxLEFT|wxRIGHT|wxTOP, 4)
89
90 hbox = wxBoxSizer(wxHORIZONTAL)
91 vbox.Add(hbox, 1, wxALL|wxEXPAND)
92 self.availprojs = wxListBox(self, ID_PROJ_AVAIL,
93 style=wxLB_EXTENDED|wxLB_SORT)
94 EVT_LISTBOX(self, ID_PROJ_AVAIL, self._OnProjAvail)
95 hbox.Add(self.availprojs, 1, wxALL|wxEXPAND|wxADJUST_MINSIZE, 4)
96 self.__FillAvailList(selectCurrent = True)
97
98 # Projection List specific actions (Import/Export/Remove)
99 buttons = wxBoxSizer(wxVERTICAL)
100 hbox.Add(buttons, 0, wxALL)
101 self.button_import = wxButton(self, ID_PROJ_IMPORT, _("Import..."))
102 EVT_BUTTON(self, ID_PROJ_IMPORT, self._OnImport)
103 buttons.Add(self.button_import, 1, wxALL|wxEXPAND, 4)
104 self.button_export = wxButton(self, ID_PROJ_EXPORT, _("Export..."))
105 EVT_BUTTON(self, ID_PROJ_EXPORT, self._OnExport)
106 buttons.Add(self.button_export, 1, wxALL|wxEXPAND, 4)
107 buttons.Add(20, 20, 0, wxEXPAND, 0)
108 self.button_remove = wxButton(self, ID_PROJ_REMOVE, _("Remove"))
109 EVT_BUTTON(self, ID_PROJ_REMOVE, self._OnRemove)
110 buttons.Add(self.button_remove, 1, wxALL|wxEXPAND, 4)
111
112 # The file path
113 self.projfilepath = wxStaticText(self, -1, "")
114 vbox.Add(self.projfilepath, 0, wxALL|wxEXPAND)
115
116 #
117 # The projection editor part
118 #
119 self.edit_box = wxStaticBox(self, -1, _("Edit"))
120 sizer_edit = wxStaticBoxSizer(self.edit_box, wxHORIZONTAL)
121 main_box.Add(sizer_edit, 1, wxALL|wxEXPAND)
122
123 # Projection Specific Entries (Name/Projection)
124 self.sizer_projctrls = wxBoxSizer(wxVERTICAL)
125 sizer_edit.Add(self.sizer_projctrls, 1, wxALL|wxEXPAND)
126
127 hbox = wxBoxSizer(wxHORIZONTAL)
128 self.sizer_projctrls.Add(hbox, 0, wxALL|wxEXPAND)
129 label = wxStaticText(self, -1, _("Name:"))
130 hbox.Add(label, 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
131 self.projname = wxTextCtrl(self, ID_PROJ_PROJNAME, "")
132 EVT_TEXT(self, ID_PROJ_PROJNAME, self._OnProjName)
133 hbox.Add(self.projname, 1, wxALL|wxEXPAND, 4)
134
135 hbox = wxBoxSizer(wxHORIZONTAL)
136 self.sizer_projctrls.Add(hbox, 0, wxALL|wxEXPAND)
137 label = wxStaticText(self, -1, _("Projection:"))
138 hbox.Add(label, 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
139 self.projchoice = wxChoice(self, ID_PROJ_PROJCHOICE)
140 self.projchoice.SetSelection(0)
141 EVT_CHOICE(self, ID_PROJ_PROJCHOICE, self._OnProjChoice)
142 hbox.Add(self.projchoice, 1, wxALL|wxEXPAND, 4)
143 # Fill the projection choice list.
144 self.nbsizer = NotebookLikeSizer()
145 self.sizer_projctrls.Add(self.nbsizer, 1,
146 wxALL|wxEXPAND|wxADJUST_MINSIZE, 3)
147 self.projection_panels = []
148 for proj_type, name, cls in self.projection_panel_defs:
149 self.projchoice.Append(name, proj_type)
150 panel = cls(self, self.receiver)
151 panel.Hide()
152 panel.projection_index = len(self.projection_panels)
153 panel.projection_type = proj_type
154 self.projection_panels.append(panel)
155 self.nbsizer.Add(panel)
156 self.unknown_projection_panel = UnknownProjPanel(self, self.receiver)
157 self.unknown_projection_panel.Hide()
158 self.nbsizer.Add(self.unknown_projection_panel)
159
160 # Projection Specific actions (New/Save/Add)
161 buttons = wxBoxSizer(wxVERTICAL)
162 sizer_edit.Add(buttons, 0, wxALL)
163 self.button_new = wxButton(self, ID_PROJ_NEW, _("New"))
164 EVT_BUTTON(self, ID_PROJ_NEW, self._OnNew)
165 buttons.Add(self.button_new, 0, wxEXPAND|wxALL, 4)
166 self.button_add = wxButton(self, ID_PROJ_ADDTOLIST, _("Add to List"))
167 EVT_BUTTON(self, ID_PROJ_ADDTOLIST, self._OnAddToList)
168 buttons.Add(self.button_add, 0, wxEXPAND|wxALL, 4)
169 buttons.Add(20, 20, 0, wxEXPAND, 0)
170 self.button_save = wxButton(self, ID_PROJ_SAVE,_("Update"))
171 EVT_BUTTON(self, ID_PROJ_SAVE, self._OnSave)
172 buttons.Add(self.button_save, 0, wxEXPAND|wxALL|wxALIGN_BOTTOM, 4)
173
174 #
175 # Main Action buttons (Try/Revert/OK/Close)
176 #
177 buttons = wxBoxSizer(wxHORIZONTAL)
178 top_box.Add(buttons, 0, wxALL|wxALIGN_RIGHT, 10)
179 self.button_try = wxButton(self, wxID_APPLY, _("Try"))
180 EVT_BUTTON(self, wxID_APPLY, self.OnApply)
181 buttons.Add(self.button_try, 0, wxRIGHT, 10)
182 self.button_revert = wxButton(self, ID_PROJ_REVERT, _("Revert"))
183 EVT_BUTTON(self, ID_PROJ_REVERT, self._OnRevert)
184 buttons.Add(self.button_revert, 0, wxRIGHT, 10)
185 self.button_ok = wxButton(self, wxID_OK, _("OK"))
186 EVT_BUTTON(self, wxID_OK, self.OnOK)
187 self.button_ok.SetDefault()
188 buttons.Add(self.button_ok, 0, wxRIGHT, 10)
189 self.button_close = wxButton(self, wxID_CANCEL, _("Close"))
190 EVT_BUTTON(self, wxID_CANCEL, self.OnCancel)
191 buttons.Add(self.button_close, 0, wxRIGHT, 10)
192
193
194 #
195 # Automatic Layout
196 #
197 self.SetAutoLayout(1)
198 self.SetSizer(top_box)
199 top_box.Fit(self)
200 top_box.SetSizeHints(self)
201
202 def OnApply(self, event):
203 self.__SetProjection()
204 self.haveTried = True
205
206 def OnOK(self, event):
207 self.__SetProjection()
208 self.Close()
209
210 def OnCancel(self, event):
211 """Cancel just closes the dialog, but we call it cancel so we
212 can overload the functionality of wxDialog.
213 """
214 self.Close()
215
216 def _OnRevert(self, event):
217 if self.haveTried:
218 self.receiver.SetProjection(self.originalProjection)
219 self.haveTried = False
220
221 def _OnNew(self, event):
222
223 # clear all selections
224 sel = self.availprojs.GetSelections()
225 for index in sel:
226 self.availprojs.SetSelection(index, False)
227
228 self.projname.Clear()
229
230 # supply a projection panel if there wasn't one
231 if self.curProjPanel is None:
232 self.projchoice.SetSelection(0)
233 self.__DoOnProjChoice()
234
235 self.curProjPanel.Clear()
236
237 def _OnSave(self, event):
238
239 sel = self.availprojs.GetSelections()
240 assert len(sel) == 1, "button shouldn't be enabled"
241
242 proj, projfile = self.availprojs.GetClientData(sel[0])
243
244 assert proj is not None and projfile is not None
245
246 newproj = self.__GetProjection()
247
248 if newproj is not None:
249 projfile.Replace(proj, newproj)
250 self.write_proj_file(projfile)
251 self.availprojs.SetClientData(sel[0], [newproj, projfile])
252
253 self.__FillAvailList( selectProj = newproj.Label())
254
255 def _OnAddToList(self, event):
256
257 proj = self.__GetProjection()
258 if proj is not None:
259 self.__usrProjFile.Add(proj)
260 self.write_proj_file(self.__usrProjFile)
261 self.__FillAvailList( selectProj = proj.Label())
262
263 def _OnProjAvail(self, event):
264 self.__DoOnProjAvail()
265
266 def show_warnings(self, title, filename, warnings):
267 """Show the warnings (a list of strings) in a dialog
268
269 If the list is empty no dialog will be shown.
270 """
271 if warnings:
272 text = (_('Warnings when reading "%s":\n\n%s')
273 % (filename, "\n\n".join(warnings)))
274 self.parent.RunMessageBox(title, text)
275
276 def _OnImport(self, event):
277
278 dlg = wxFileDialog(self, _("Import"), style = wxOPEN)
279
280 if dlg.ShowModal() == wxID_OK:
281 path = dlg.GetPath()
282
283 ThubanBeginBusyCursor()
284 try:
285 try:
286 projFile, warnings = read_proj_file(path)
287 except IOError, (errno, errstr):
288 self.__ShowError(dlg.GetPath(), errstr)
289 else:
290 self.show_warnings(_("Warnings"), path, warnings)
291 for proj in projFile.GetProjections():
292 self.__usrProjFile.Add(proj)
293 self.write_proj_file(self.__usrProjFile)
294 finally:
295 ThubanEndBusyCursor()
296
297 self.__FillAvailList()
298
299 dlg.Destroy()
300
301 def _OnExport(self, event):
302
303 sel = self.availprojs.GetSelections()
304 assert len(sel) != 0, "button should be disabled"
305
306 dlg = wxFileDialog(self, _("Export"),
307 style = wxSAVE|wxOVERWRITE_PROMPT)
308
309 if dlg.ShowModal() == wxID_OK:
310 path = dlg.GetPath()
311
312 projFile = ProjFile(path)
313
314 for i in sel:
315 proj = self.availprojs.GetClientData(i)[CLIENT_PROJ]
316 if proj is not None:
317 projFile.Add(proj)
318
319 self.write_proj_file(projFile)
320
321 dlg.Destroy()
322
323 def _OnRemove(self, event):
324
325 sel = self.availprojs.GetSelections()
326 assert len(sel) != 0, "button should be disabled!"
327
328 #
329 # remove the items backwards so the indices don't change
330 #
331 sel = list(sel)
332 sel.sort()
333 sel.reverse()
334
335 newselection = -1
336 if len(sel) == 1:
337 newselection = sel[0] - 1
338 if newselection < 0:
339 newselection = 0
340
341 for i in sel:
342 proj, projfile = self.availprojs.GetClientData(i)
343
344 #
345 # this could be the case if they selected <None> or
346 # the currently used projection
347 #
348 if proj is not None and projfile is not None:
349 projfile.Remove(proj)
350
351 self.write_proj_file(projfile)
352
353 self.__FillAvailList()
354
355 #
356 # this *could* produce incorrect results if the .proj files
357 # change between the last list update and this selection
358 # because the list has been repopulated.
359 #
360 if newselection != -1 and self.availprojs.GetCount() > 0:
361 self.availprojs.SetSelection(newselection)
362
363 self.__VerifyButtons()
364
365 def _OnProjName(self, event):
366 self.__VerifyButtons()
367
368 def __ShowError(self, filename, errstr):
369 wxMessageDialog(self,
370 _("The following error occured:\n") +
371 filename + "\n" + errstr,
372 _("Error"), wxOK | wxICON_ERROR).ShowModal()
373
374 def __VerifyButtons(self):
375 """Enable or disable the appropriate buttons based on the
376 current state of the dialog.
377 """
378
379 sel = self.availprojs.GetSelections()
380
381 self.button_import.Enable(True)
382 self.button_export.Enable(True)
383 self.button_save.Enable(True)
384 self.button_remove.Enable(True)
385
386 self.edit_box.Enable(True)
387
388 for ctrl in [self.button_import,
389 self.button_export,
390 self.button_remove,
391 self.button_save,
392 self.button_add,
393 self.projchoice,
394 self.projname,
395 self.edit_box]:
396 ctrl.Enable(True)
397
398 if self.curProjPanel is not None:
399 self.curProjPanel.Enable(True)
400
401 if len(sel) == 0:
402 self.button_import.Enable(True)
403 self.button_export.Enable(False)
404 self.button_remove.Enable(False)
405 self.button_save.Enable(False)
406
407 elif len(sel) == 1:
408
409 proj, projFile = self.availprojs.GetClientData(sel[0])
410
411 self.button_save.Enable(len(self.projname.GetValue()) > 0)
412 self.button_add.Enable(len(self.projname.GetValue()) > 0)
413
414 if proj is None:
415 # <None> is selected
416 for ctrl in [self.button_export,
417 self.button_remove,
418 self.button_save,
419 self.button_add,
420 self.projchoice,
421 self.projname]:
422 ctrl.Enable(False)
423
424 if self.curProjPanel is not None:
425 self.curProjPanel.Enable(False)
426
427 elif proj is self.originalProjection:
428 self.button_remove.Enable(False)
429
430 if projFile is None:
431 self.button_save.Enable(False)
432
433 else:
434 self.edit_box.Enable(False)
435
436 def __DoOnProjAvail(self):
437
438 sel = self.availprojs.GetSelections()
439 if len(sel) == 1:
440
441 proj = self.availprojs.GetClientData(sel[0])[CLIENT_PROJ]
442 projfile = self.availprojs.GetClientData(sel[0])[CLIENT_PROJFILE]
443
444 if proj is None:
445 # user selected <None>
446 self.projname.Clear()
447 self.projfilepath.SetLabel(_("Projection File: "))
448 else:
449
450 if projfile is not None:
451 self.projfilepath.SetLabel(_("Projection File: ") +
452 os.path.basename(projfile.GetFilename()))
453 else:
454 # only None if the currently used projection is selected
455 self.projfilepath.SetLabel(_("Projection File: "))
456
457 self.projname.SetValue(proj.Label())
458
459 myProjType = proj.GetParameter("proj")
460 i = 0
461 for projType, name, cls in self.projection_panel_defs:
462 if myProjType == projType:
463 self.projchoice.Enable(True)
464 self.projchoice.SetSelection(i)
465 self.__DoOnProjChoice()
466
467 #
468 # self.curProjPanel should not be null
469 # after a call to __DoOnProjChoice
470 #
471 assert self.curProjPanel is not None
472
473 self.curProjPanel.SetProjection(proj)
474 break
475 i += 1
476 else:
477 self.projchoice.Disable()
478 self._show_proj_panel(UnknownProjPanel)
479
480 self.__VerifyButtons()
481
482 def _OnProjChoice(self, event):
483 self.__DoOnProjChoice()
484
485 def __DoOnProjChoice(self):
486 """Create and layout a projection panel based on the selected
487 projection type.
488
489 This is necessary to have in seperate method since calls to
490 wxChoice.SetSelection() do not trigger an event.
491
492 At the end of this method self.curProjPanel will not be None
493 if there was a item selected.
494 """
495 choice = self.projchoice
496
497 sel = choice.GetSelection()
498 if sel != -1:
499 proj_type = choice.GetClientData(sel)
500 for t, name, cls in self.projection_panel_defs:
501 if t == proj_type:
502 self._show_proj_panel(cls)
503 break
504 # FIXME: what to do if sel == -1?
505
506 def _show_proj_panel(self, panel_class):
507 """Show the panel as the projection panel"""
508 if panel_class is UnknownProjPanel:
509 self.edit_box.Disable()
510 self.nbsizer.Activate(self.unknown_projection_panel)
511 self.curProjPanel = self.unknown_projection_panel
512 else:
513 self.edit_box.Enable(True)
514 self.unknown_projection_panel.Hide()
515 for panel in self.projection_panels:
516 if panel.__class__ is panel_class:
517 self.nbsizer.Activate(panel)
518 self.curProjPanel = panel
519
520 def __SetProjection(self):
521 """Set the receiver's projection."""
522
523 #
524 # save the original projection only once in case
525 # we try to apply several different projections
526 #
527 self.receiver.SetProjection(self.__GetProjection())
528
529 def __GetProjection(self):
530 """Return a suitable Projection object based on the current
531 state of the dialog box selections.
532
533 Could be None.
534 """
535
536 sel = self.availprojs.GetSelections()
537 assert len(sel) < 2, "button should be disabled"
538
539
540 if len(sel) == 1:
541 proj = self.availprojs.GetClientData(sel[0])[CLIENT_PROJ]
542 if proj is None:
543 # <None> is selected
544 return None
545
546 #
547 # self.curProjPanel should always contain the most
548 # relevant data for a projection
549 #
550 if self.curProjPanel is not None:
551 return Projection(self.curProjPanel.GetParameters(),
552 self.projname.GetValue())
553
554 return None
555
556 def __FillAvailList(self, selectCurrent = False, selectProj = None):
557 """Populate the list of available projections.
558
559 selectCurrent -- if True, select the projection used by
560 the receiver, otherwise select nothing.
561 selectProj -- if set, select the projection found under the
562 specified name. This overwrites any other
563 selection estimate.
564 """
565
566 self.availprojs.Clear()
567
568 #
569 # the list can never be empty. there will always be
570 # at least this one item
571 #
572 self.availprojs.Append(_("<None>"), (None, None))
573
574 ThubanBeginBusyCursor()
575 try:
576 projfile, warnings = get_system_proj_file()
577 self.show_warnings(_("Warnings"), projfile.GetFilename(), warnings)
578 for proj in projfile.GetProjections():
579 self.availprojs.Append(proj.Label(), [proj, projfile])
580 self.__sysProjFile = projfile
581
582 projfile, warnings = get_user_proj_file()
583 self.show_warnings(_("Warnings"), projfile.GetFilename(), warnings)
584 for proj in projfile.GetProjections():
585 self.availprojs.Append(proj.Label(), [proj, projfile])
586 self.__usrProjFile = projfile
587 finally:
588 ThubanEndBusyCursor()
589
590 #
591 # We add the current projection to the list at last.
592 # Since the list is resorted immediately a following FindString()
593 # determines the index correctly.
594 #
595 proj = self.receiver.GetProjection()
596 if proj is not None:
597 proj_item = _("%s (current)") % proj.Label()
598 self.availprojs.Append(proj_item, [proj, None])
599 if selectCurrent:
600 self.availprojs.SetSelection(
601 self.availprojs.FindString(proj_item)
602 )
603 else:
604 if selectCurrent:
605 self.availprojs.SetSelection(
606 self.availprojs.FindString(_("<None>"))
607 )
608 if selectProj:
609 self.availprojs.SetSelection(
610 self.availprojs.FindString(selectProj)
611 )
612
613 def write_proj_file(self, proj_file):
614 """Write the ProjFile object proj_file back to its file
615
616 Show a busy cursor while writing and if an error occurs show a
617 dialog with the error message.
618 """
619 try:
620 ThubanBeginBusyCursor()
621 try:
622 write_proj_file(proj_file)
623 finally:
624 ThubanEndBusyCursor()
625 except IOError, (errno, errstr):
626 self.__ShowError(proj_file.GetFilename(), errstr)
627
628
629
630 class ProjPanel(wxPanel):
631 """Base class for all projection panels."""
632
633 def __init__(self, parent):
634 wxPanel.__init__(self, parent, -1)
635
636 self.__ellps = wxChoice(self, -1)
637 self.ellpsData = [("airy" , _("Airy")),
638 ("bessel", _("Bessel 1841")),
639 ("clrk66", _("Clarke 1866")),
640 ("clrk80", _("Clarke 1880")),
641 ("GRS80" , _("GRS 1980 (IUGG, 1980)")),
642 ("intl" , _("International 1909 (Hayford)")),
643 ("WGS84" , _("WGS 84"))]
644
645 for tag, name in self.ellpsData:
646 self.__ellps.Append(name, tag)
647
648 self.__ellps.SetSelection(0)
649
650 def _DoLayout(self, childPanel = None):
651
652 panelSizer = wxBoxSizer(wxVERTICAL)
653
654 sizer = wxBoxSizer(wxHORIZONTAL)
655 sizer.Add(wxStaticText(self, -1, _("Ellipsoid:")), 0,
656 wxALL|wxALIGN_CENTER_VERTICAL, 4)
657 sizer.Add(self.__ellps, 1, wxALL|wxALIGN_CENTER_VERTICAL, 4)
658 panelSizer.Add(sizer, 0, wxALL|wxEXPAND, 4)
659
660 if childPanel is not None:
661 panelSizer.Add(childPanel, 0, wxEXPAND, 0)
662
663 self.SetAutoLayout(1)
664 self.SetSizer(panelSizer)
665 panelSizer.Fit(self)
666 panelSizer.SetSizeHints(self)
667 self.Layout()
668
669 def SetProjection(self, proj):
670 if proj is not None:
671 param = proj.GetParameter("ellps")
672 i = 0
673 for tag, name in self.ellpsData:
674 if param == tag:
675 self.__ellps.SetSelection(i)
676 return # returning early!
677 i += 1
678
679 #
680 # if proj is none, or the parameter couldn't be found...
681 #
682 self.__ellps.SetSelection(0)
683
684 def GetParameters(self):
685 return ["ellps=" + self.__ellps.GetClientData(
686 self.__ellps.GetSelection())]
687
688
689 ID_TMPANEL_LAT = 4001
690 ID_TMPANEL_LONG = 4002
691 ID_TMPANEL_FASLE_EAST = 4003
692 ID_TMPANEL_FALSE_NORTH = 4004
693 ID_TMPANEL_SCALE = 4005
694
695 class UnknownProjPanel(ProjPanel):
696
697 """Panel for unknown projection types"""
698
699 def __init__(self, parent, receiver):
700 ProjPanel.__init__(self, parent)
701
702 self._DoLayout()
703
704 def _DoLayout(self):
705 sizer = wxBoxSizer(wxVERTICAL)
706
707 sizer.Add(wxStaticText(self, -1,
708 _("Thuban does not know the parameters\n"
709 "for the current projection and cannot\n"
710 "display a configuration panel.")))
711
712 ProjPanel._DoLayout(self, sizer)
713
714 def GetProjName(self):
715 return "Unknown"
716
717 def SetProjection(self, proj):
718 pass
719
720 def GetParameters(self):
721 return None
722
723 class TMPanel(ProjPanel):
724 """Projection panel for Transverse Mercator."""
725
726 def __init__(self, parent, receiver):
727 ProjPanel.__init__(self, parent)
728
729 self.__latitude = wxTextCtrl(self, ID_TMPANEL_LAT)
730 self.__longitude = wxTextCtrl(self, ID_TMPANEL_LONG)
731 self.__scale = wxTextCtrl(self, ID_TMPANEL_SCALE)
732 self.__falseEast = wxTextCtrl(self, ID_TMPANEL_FASLE_EAST)
733 self.__falseNorth = wxTextCtrl(self, ID_TMPANEL_FALSE_NORTH)
734
735 self._DoLayout()
736
737 def _DoLayout(self):
738
739 sizer = wxFlexGridSizer(4, 2, 0, 0)
740 sizer.Add(wxStaticText(self, -1, _("Latitude:")), 0, wxALL, 4)
741 sizer.Add(self.__latitude, 0, wxALL, 4)
742 sizer.Add(wxStaticText(self, -1, _("Longitude:")), 0, wxALL, 4)
743 sizer.Add(self.__longitude, 0, wxALL, 4)
744 sizer.Add(wxStaticText(self, -1, _("False Easting:")), 0, wxALL, 4)
745 sizer.Add(self.__falseEast, 0, wxALL, 4)
746 sizer.Add(wxStaticText(self, -1, _("False Northing:")), 0, wxALL, 4)
747 sizer.Add(self.__falseNorth, 0, wxALL, 4)
748 sizer.Add(wxStaticText(self, -1, _("Scale Factor:")), 0, wxALL, 4)
749 sizer.Add(self.__scale, 0, wxALL, 4)
750
751 ProjPanel._DoLayout(self, sizer)
752
753 def GetProjName(self):
754 return _("Transverse Mercator")
755
756 def SetProjection(self, proj):
757 ProjPanel.SetProjection(self, proj)
758
759 self.__latitude.SetValue(proj.GetParameter("lat_0"))
760 self.__longitude.SetValue(proj.GetParameter("lon_0"))
761 self.__falseEast.SetValue(proj.GetParameter("x_0"))
762 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
763 self.__scale.SetValue(proj.GetParameter("k"))
764
765 ProjPanel.SetProjection(self, proj)
766
767 def GetParameters(self):
768 params = ["proj=tmerc",
769 "lat_0=" + self.__latitude.GetValue(),
770 "lon_0=" + self.__longitude.GetValue(),
771 "x_0=" + self.__falseEast.GetValue(),
772 "y_0=" + self.__falseNorth.GetValue(),
773 "k=" + self.__scale.GetValue()]
774 params.extend(ProjPanel.GetParameters(self))
775 return params
776
777 def Clear(self):
778 self.__latitude.Clear()
779 self.__longitude.Clear()
780 self.__falseEast.Clear()
781 self.__falseNorth.Clear()
782 self.__scale.Clear()
783
784 ProjPanel.Clear(self)
785
786 ID_UTMPANEL_ZONE = 4001
787 ID_UTMPANEL_SOUTH = 4002
788 ID_UTMPANEL_PROP = 4003
789
790 class UTMPanel(ProjPanel):
791 """Projection Panel for Universal Transverse Mercator."""
792
793 def __init__(self, parent, receiver):
794 ProjPanel.__init__(self, parent)
795
796 self.receiver = receiver
797
798 self.__zone = wxSpinCtrl(self, ID_UTMPANEL_ZONE, "1", min=1, max=60)
799 self.__propButton = wxButton(self, ID_UTMPANEL_PROP, _("Propose"))
800 self.__south = wxCheckBox(self, ID_UTMPANEL_SOUTH,
801 _("Southern Hemisphere"))
802
803 self._DoLayout()
804
805 EVT_BUTTON(self, ID_UTMPANEL_PROP, self._OnPropose)
806
807 def _DoLayout(self):
808
809 sizer = wxBoxSizer(wxVERTICAL)
810 psizer = wxBoxSizer(wxHORIZONTAL)
811 psizer.Add(wxStaticText(self, -1, _("Zone:")), 0, wxALL, 4)
812 psizer.Add(self.__zone, 0, wxALL, 4)
813 psizer.Add(self.__propButton, 0, wxALL, 4)
814 sizer.Add(psizer, 0, wxALL, 4)
815 sizer.Add(self.__south, 0, wxALL, 4)
816
817 ProjPanel._DoLayout(self, sizer)
818
819 def GetProjName(self):
820 return _("Universal Transverse Mercator")
821
822 def SetProjection(self, proj):
823 self.__zone.SetValue(int(proj.GetParameter("zone")))
824 self.__south.SetValue(proj.GetParameter("south") != "")
825 ProjPanel.SetProjection(self, proj)
826
827 def GetParameters(self):
828 params = ["proj=utm", "zone=" + str(self.__zone.GetValue())]
829 if self.__south.IsChecked():
830 params.append("south")
831
832 params.extend(ProjPanel.GetParameters(self))
833 return params
834
835 def Clear(self):
836 self.__zone.SetValue(1)
837 self.__south.SetValue(False)
838 ProjPanel.Clear(self)
839
840 def _OnPropose(self, event):
841 """Call the propose dialog.
842 If the receiver (e.g. the current map) has no bounding box,
843 inform the user accordingly.
844 """
845 bb = self.receiver.BoundingBox()
846 if bb is None:
847 dlg = wxMessageDialog(self,
848 _("Can not propose: No bounding box found."),
849 _("Projection: Propose UTM Zone"),
850 wxOK | wxICON_INFORMATION)
851 dlg.CenterOnParent()
852 result = dlg.ShowModal()
853 dlg.Destroy()
854 return
855
856 dlg = UTMProposeZoneDialog(self, self.receiver.BoundingBox())
857 if dlg.ShowModal() == wxID_OK:
858 self.__zone.SetValue(dlg.GetProposedZone())
859
860 class LCCPanel(ProjPanel):
861 """Projection Panel for Lambert Conic Conformal."""
862
863 def __init__(self, parent, receiver):
864 ProjPanel.__init__(self, parent)
865
866 self.__fspLatitude = wxTextCtrl(self, -1)
867 self.__sspLatitude = wxTextCtrl(self, -1)
868 self.__originLat = wxTextCtrl(self, -1)
869 self.__meridian = wxTextCtrl(self, -1)
870 self.__falseEast = wxTextCtrl(self, -1)
871 self.__falseNorth = wxTextCtrl(self, -1)
872
873 self._DoLayout()
874
875 def _DoLayout(self):
876
877 sizer = wxFlexGridSizer(6, 2, 0, 0)
878 sizer.Add(wxStaticText(self, -1,
879 _("Latitude of first standard parallel:")))
880 sizer.Add(self.__fspLatitude, 0, wxALL, 4)
881 sizer.Add(wxStaticText(self, -1,
882 _("Latitude of second standard parallel:")))
883 sizer.Add(self.__sspLatitude, 0, wxALL, 4)
884 sizer.Add(wxStaticText(self, -1, _("Central Meridian:")))
885 sizer.Add(self.__meridian, 0, wxALL, 4)
886 sizer.Add(wxStaticText(self, -1, _("Latitude of origin:")))
887 sizer.Add(self.__originLat, 0, wxALL, 4)
888 sizer.Add(wxStaticText(self, -1, _("False Easting:")))
889 sizer.Add(self.__falseEast, 0, wxALL, 4)
890 sizer.Add(wxStaticText(self, -1, _("False Northing:")))
891 sizer.Add(self.__falseNorth, 0, wxALL, 4)
892
893 ProjPanel._DoLayout(self, sizer)
894
895 def GetProjName(self):
896 return _("Lambert Conic Conformal")
897
898 def SetProjection(self, proj):
899 self.__fspLatitude.SetValue(proj.GetParameter("lat_1"))
900 self.__sspLatitude.SetValue(proj.GetParameter("lat_2"))
901 self.__originLat.SetValue(proj.GetParameter("lat_0"))
902 self.__meridian.SetValue(proj.GetParameter("lon_0"))
903 self.__falseEast.SetValue(proj.GetParameter("x_0"))
904 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
905
906 ProjPanel.SetProjection(self, proj)
907
908 def GetParameters(self):
909 params = ["proj=lcc",
910 "lat_1=" + self.__fspLatitude.GetValue(),
911 "lat_2=" + self.__sspLatitude.GetValue(),
912 "lat_0=" + self.__originLat.GetValue(),
913 "lon_0=" + self.__meridian.GetValue(),
914 "x_0=" + self.__falseEast.GetValue(),
915 "y_0=" + self.__falseNorth.GetValue()]
916
917 params.extend(ProjPanel.GetParameters(self))
918 return params
919
920 def Clear(self):
921 self.__fspLatitude.Clear()
922 self.__sspLatitude.Clear()
923 self.__originLat.Clear()
924 self.__meridian.Clear()
925 self.__falseEast.Clear()
926 self.__falseNorth.Clear()
927
928 ProjPanel.Clear(self)
929
930 class GeoPanel(ProjPanel):
931 """Projection Panel for a Geographic Projection."""
932
933 def __init__(self, parent, receiver):
934 ProjPanel.__init__(self, parent)
935
936 self.__choices = [(_("Degrees"), "0.017453"),
937 (_("Radians"), "1")]
938
939 self.__scale = wxChoice(self, -1)
940 for choice, value in self.__choices:
941 self.__scale.Append(choice, value)
942
943 self._DoLayout()
944
945 def GetProjName(self):
946 return _("Geographic")
947
948 def SetProjection(self, proj):
949 value = proj.GetParameter("to_meter")
950 for i in range(len(self.__choices)):
951 choice, data = self.__choices[i]
952 if value == data:
953 self.__scale.SetSelection(i)
954 ProjPanel.SetProjection(self, proj)
955
956 def GetParameters(self):
957 params = ["proj=latlong",
958 "to_meter=%s" % self.__scale.GetClientData(
959 self.__scale.GetSelection())]
960
961 params.extend(ProjPanel.GetParameters(self))
962 return params
963
964 def Clear(self):
965 ProjPanel.Clear(self)
966
967 def _DoLayout(self):
968 sizer = wxBoxSizer(wxHORIZONTAL)
969
970 sizer.Add(wxStaticText(self, -1, _("Source Data is in: ")),
971 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
972 sizer.Add(self.__scale, 1, wxEXPAND|wxALL, 4)
973
974 self.__scale.SetSelection(0)
975
976 ProjPanel._DoLayout(self, sizer)
977
978
979 ID_UTM_PROPOSE_ZONE_DIALOG_TAKE = 4001
980 ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL = 4002
981 class UTMProposeZoneDialog(wxDialog):
982
983 """Propose a sensible Zone considering the current map extent."""
984
985 def __init__(self, parent, (x, y, x2, y2)):
986 wxDialog.__init__(self, parent, -1, _("Projection: Propose UTM Zone"),
987 wxDefaultPosition, wxSize(200, 100))
988 self.parent = parent
989 x = x + 180
990 x2 = x2 + 180
991 center = (x2 - x) / 2 + x
992 self.proposedZone = int(center / 6 + 1)
993 self.dialogLayout()
994
995 def dialogLayout(self):
996 topBox = wxBoxSizer(wxVERTICAL)
997
998 textBox = wxBoxSizer(wxVERTICAL)
999 textBox.Add(wxStaticText(self, -1, _("The current map extent center "
1000 "lies in UTM Zone")),
1001 0, wxALIGN_CENTER|wxALL, 4)
1002 textBox.Add(wxStaticText(self, -1, str(self.proposedZone)),
1003 0, wxALIGN_CENTER|wxALL, 4)
1004
1005 topBox.Add(textBox, 1, wxEXPAND|wxALL, 4)
1006
1007 buttonBox = wxBoxSizer(wxHORIZONTAL)
1008 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE,
1009 _("Take")), 0, wxALL, 4)
1010 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL,
1011 _("Cancel")), 0, wxALL, 4)
1012 topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
1013 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE, self.OnTake)
1014 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL, self.OnCancel)
1015
1016 self.SetAutoLayout(True)
1017 self.SetSizer(topBox)
1018 topBox.Fit(self)
1019 topBox.SetSizeHints(self)
1020
1021 def OnTake(self, event):
1022 self.EndModal(wxID_OK)
1023
1024 def OnCancel(self, event):
1025 self.EndModal(wxID_CANCEL)
1026
1027 def GetProposedZone(self):
1028 return self.proposedZone

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26