/[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 1851 - (show annotations)
Tue Oct 21 14:17:24 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: 34295 byte(s)
Rework the projection dialog to fix a few bugs, including RT 2166
and most of 2168

(ProjFrame): Substantial changes
throughout the class. The main change is to use the ProjectionList
class instead of a normal wxListBox. Also, add an explicit
"Unknown" projection to the projection choice control.
(ProjPanel.__init__): Add an "unknown" ellipsoid
(TMPanel.__init__, LCCPanel.__init__): Tweak the order of
instantiation of the panel's controls to make the tab-order more
natural

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