/[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 1854 - (show annotations)
Wed Oct 22 09:38:36 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: 34554 byte(s)
(ProjFrame.__init__): Do not set the
focus on the OK button, only on the projection list. That way the
list really has the focus initially
(ProjFrame.OnClose): Call the projection list's Destroy method to
make it unsubscribe all messages

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