/[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 1858 - (show annotations)
Fri Oct 24 15:12:58 2003 UTC (21 years, 4 months ago) by jan
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 35085 byte(s)
(ProjFrame.proj_selection_changed): Set the projection even for the
UnknownPanel.
(UnknownProjPanel.__init__): Define the text and create the textctrl
widget.
(UnknownProjPanel._DoLayout): Replaced static text widget by the
textctrl created in __init__.
(UnknownProjPanel.SetProjection): Set the text for the text ctrl
including the parameters of the projection.

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 assert self.curProjPanel is not None
467 self.curProjPanel.SetProjection(proj)
468 else:
469 self.projfilepath.SetLabel(_("Multiple Projections selected"))
470
471 self.__VerifyButtons()
472
473 def _OnProjChoice(self, event):
474 self.__DoOnProjChoice()
475
476 def __DoOnProjChoice(self):
477 """Create and layout a projection panel based on the selected
478 projection type.
479
480 This is necessary to have in seperate method since calls to
481 wxChoice.SetSelection() do not trigger an event.
482
483 At the end of this method self.curProjPanel will not be None
484 if there was a item selected.
485 """
486 choice = self.projchoice
487
488 sel = choice.GetSelection()
489 if sel != -1:
490 proj_type = choice.GetClientData(sel)
491 for t, name, cls in self.projection_panel_defs:
492 if t == proj_type:
493 self._show_proj_panel(cls)
494 break
495 # FIXME: what to do if sel == -1?
496
497 def _show_proj_panel(self, panel_class):
498 """Show the panel as the projection panel"""
499 if panel_class is UnknownProjPanel:
500 self.edit_box.Disable()
501 self.nbsizer.Activate(self.unknown_projection_panel)
502 self.curProjPanel = self.unknown_projection_panel
503 else:
504 self.edit_box.Enable(True)
505 self.unknown_projection_panel.Hide()
506 for panel in self.projection_panels:
507 if panel.__class__ is panel_class:
508 self.nbsizer.Activate(panel)
509 self.curProjPanel = panel
510
511 def __SetProjection(self):
512 """Set the receiver's projection."""
513
514 #
515 # save the original projection only once in case
516 # we try to apply several different projections
517 #
518 self.receiver.SetProjection(self.__GetProjection())
519
520 def __GetProjection(self):
521 """Return a suitable Projection object based on the current
522 state of the dialog box selections.
523
524 Could be None.
525 """
526
527 assert self.projection_list.GetSelectedItemCount() < 2, \
528 "button should be disabled"
529
530 sel = self.projection_list.selected_projections()
531 if len(sel) == 1:
532 if sel[0][0] is None:
533 # <None> is selected
534 return None
535
536 # self.curProjPanel should always contain the most relevant data
537 # for a projection
538 if self.curProjPanel is not None:
539 return Projection(self.curProjPanel.GetParameters(),
540 self.projname.GetValue())
541
542 return None
543
544 def load_user_proj(self):
545 ThubanBeginBusyCursor()
546 try:
547 if self.__usrProjFile is None:
548 projfile, warnings = get_user_proj_file()
549 self.show_warnings(_("Warnings"), projfile.GetFilename(),
550 warnings)
551 self.__usrProjFile = projfile
552 return self.__usrProjFile
553 finally:
554 ThubanEndBusyCursor()
555
556 def load_system_proj(self):
557 ThubanBeginBusyCursor()
558 try:
559 if self.__sysProjFile is None:
560 projfile, warnings = get_system_proj_file()
561 self.show_warnings(_("Warnings"), projfile.GetFilename(),
562 warnings)
563 self.__sysProjFile = projfile
564 return self.__sysProjFile
565 finally:
566 ThubanEndBusyCursor()
567
568 def write_proj_file(self, proj_file):
569 """Write the ProjFile object proj_file back to its file
570
571 Show a busy cursor while writing and if an error occurs show a
572 dialog with the error message.
573 """
574 try:
575 ThubanBeginBusyCursor()
576 try:
577 write_proj_file(proj_file)
578 finally:
579 ThubanEndBusyCursor()
580 except IOError, (errno, errstr):
581 self.__ShowError(proj_file.GetFilename(), errstr)
582
583
584
585 class ProjPanel(wxPanel):
586 """Base class for all projection panels."""
587
588 def __init__(self, parent):
589 wxPanel.__init__(self, parent, -1)
590
591 self.__ellps = wxChoice(self, -1)
592 self.ellpsData = [("", _("<Unknown>")),
593 ("airy" , _("Airy")),
594 ("bessel", _("Bessel 1841")),
595 ("clrk66", _("Clarke 1866")),
596 ("clrk80", _("Clarke 1880")),
597 ("GRS80" , _("GRS 1980 (IUGG, 1980)")),
598 ("intl" , _("International 1909 (Hayford)")),
599 ("WGS84" , _("WGS 84"))]
600
601 for tag, name in self.ellpsData:
602 self.__ellps.Append(name, tag)
603
604 self.__ellps.SetSelection(0)
605
606 def _DoLayout(self, childPanel = None):
607
608 panelSizer = wxBoxSizer(wxVERTICAL)
609
610 sizer = wxBoxSizer(wxHORIZONTAL)
611 sizer.Add(wxStaticText(self, -1, _("Ellipsoid:")), 0,
612 wxALL|wxALIGN_CENTER_VERTICAL, 4)
613 sizer.Add(self.__ellps, 1, wxALL|wxALIGN_CENTER_VERTICAL, 4)
614 panelSizer.Add(sizer, 0, wxALL|wxEXPAND, 4)
615
616 if childPanel is not None:
617 panelSizer.Add(childPanel, 0, wxEXPAND, 0)
618
619 self.SetAutoLayout(1)
620 self.SetSizer(panelSizer)
621 panelSizer.Fit(self)
622 panelSizer.SetSizeHints(self)
623 self.Layout()
624
625 def SetProjection(self, proj):
626 if proj is not None:
627 param = proj.GetParameter("ellps")
628 i = 0
629 for tag, name in self.ellpsData:
630 if param == tag:
631 self.__ellps.SetSelection(i)
632 return # returning early!
633 i += 1
634
635 #
636 # if proj is none, or the parameter couldn't be found...
637 #
638 self.__ellps.SetSelection(0)
639
640 def GetParameters(self):
641 ellps = self.__ellps.GetSelection()
642 if ellps > 0:
643 return ["ellps=" + self.__ellps.GetClientData(ellps)]
644 return []
645
646
647 ID_TMPANEL_LAT = 4001
648 ID_TMPANEL_LONG = 4002
649 ID_TMPANEL_FASLE_EAST = 4003
650 ID_TMPANEL_FALSE_NORTH = 4004
651 ID_TMPANEL_SCALE = 4005
652
653 class UnknownProjPanel(ProjPanel):
654
655 """Panel for unknown projection types"""
656
657 def __init__(self, parent, receiver):
658 ProjPanel.__init__(self, parent)
659
660 self.__text = _("Thuban does not know the parameters\n"
661 "for the current projection and cannot\n"
662 "display a configuration panel.\n\n"
663 "The unidentified set of parameters is:\n\n")
664
665 self.__textbox = wxTextCtrl(self, -1, self.__text, size=(100,200),
666 style=wxTE_READONLY|wxTE_MULTILINE|wxTE_LINEWRAP)
667 self._DoLayout()
668
669 def _DoLayout(self):
670 sizer = wxBoxSizer(wxVERTICAL)
671
672 sizer.Add(self.__textbox, 0, wxALL|wxEXPAND, 4)
673
674 ProjPanel._DoLayout(self, sizer)
675
676 def GetProjName(self):
677 return "Unknown"
678
679 def SetProjection(self, proj):
680 """Append the available parameters to the info text."""
681 text = self.__text
682 for param in proj.GetAllParameters():
683 text = text + '%s\n' % param
684 self.__textbox.SetValue(text)
685
686 def GetParameters(self):
687 return None
688
689 class TMPanel(ProjPanel):
690 """Projection panel for Transverse Mercator."""
691
692 def __init__(self, parent, receiver):
693 ProjPanel.__init__(self, parent)
694
695 self.__latitude = wxTextCtrl(self, ID_TMPANEL_LAT)
696 self.__longitude = wxTextCtrl(self, ID_TMPANEL_LONG)
697 self.__falseEast = wxTextCtrl(self, ID_TMPANEL_FASLE_EAST)
698 self.__falseNorth = wxTextCtrl(self, ID_TMPANEL_FALSE_NORTH)
699 self.__scale = wxTextCtrl(self, ID_TMPANEL_SCALE)
700
701 self._DoLayout()
702
703 def _DoLayout(self):
704
705 sizer = wxFlexGridSizer(4, 2, 0, 0)
706 sizer.Add(wxStaticText(self, -1, _("Latitude:")), 0, wxALL, 4)
707 sizer.Add(self.__latitude, 0, wxALL, 4)
708 sizer.Add(wxStaticText(self, -1, _("Longitude:")), 0, wxALL, 4)
709 sizer.Add(self.__longitude, 0, wxALL, 4)
710 sizer.Add(wxStaticText(self, -1, _("False Easting:")), 0, wxALL, 4)
711 sizer.Add(self.__falseEast, 0, wxALL, 4)
712 sizer.Add(wxStaticText(self, -1, _("False Northing:")), 0, wxALL, 4)
713 sizer.Add(self.__falseNorth, 0, wxALL, 4)
714 sizer.Add(wxStaticText(self, -1, _("Scale Factor:")), 0, wxALL, 4)
715 sizer.Add(self.__scale, 0, wxALL, 4)
716
717 ProjPanel._DoLayout(self, sizer)
718
719 def GetProjName(self):
720 return _("Transverse Mercator")
721
722 def SetProjection(self, proj):
723 ProjPanel.SetProjection(self, proj)
724
725 self.__latitude.SetValue(proj.GetParameter("lat_0"))
726 self.__longitude.SetValue(proj.GetParameter("lon_0"))
727 self.__falseEast.SetValue(proj.GetParameter("x_0"))
728 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
729 self.__scale.SetValue(proj.GetParameter("k"))
730
731 ProjPanel.SetProjection(self, proj)
732
733 def GetParameters(self):
734 params = ["proj=tmerc",
735 "lat_0=" + self.__latitude.GetValue(),
736 "lon_0=" + self.__longitude.GetValue(),
737 "x_0=" + self.__falseEast.GetValue(),
738 "y_0=" + self.__falseNorth.GetValue(),
739 "k=" + self.__scale.GetValue()]
740 params.extend(ProjPanel.GetParameters(self))
741 return params
742
743 def Clear(self):
744 self.__latitude.Clear()
745 self.__longitude.Clear()
746 self.__falseEast.Clear()
747 self.__falseNorth.Clear()
748 self.__scale.Clear()
749
750 ProjPanel.Clear(self)
751
752 ID_UTMPANEL_ZONE = 4001
753 ID_UTMPANEL_SOUTH = 4002
754 ID_UTMPANEL_PROP = 4003
755
756 class UTMPanel(ProjPanel):
757 """Projection Panel for Universal Transverse Mercator."""
758
759 def __init__(self, parent, receiver):
760 ProjPanel.__init__(self, parent)
761
762 self.receiver = receiver
763
764 self.__zone = wxSpinCtrl(self, ID_UTMPANEL_ZONE, "1", min=1, max=60)
765 self.__propButton = wxButton(self, ID_UTMPANEL_PROP, _("Propose"))
766 self.__south = wxCheckBox(self, ID_UTMPANEL_SOUTH,
767 _("Southern Hemisphere"))
768
769 self._DoLayout()
770
771 EVT_BUTTON(self, ID_UTMPANEL_PROP, self._OnPropose)
772
773 def _DoLayout(self):
774
775 sizer = wxBoxSizer(wxVERTICAL)
776 psizer = wxBoxSizer(wxHORIZONTAL)
777 psizer.Add(wxStaticText(self, -1, _("Zone:")), 0, wxALL, 4)
778 psizer.Add(self.__zone, 0, wxALL, 4)
779 psizer.Add(self.__propButton, 0, wxALL, 4)
780 sizer.Add(psizer, 0, wxALL, 4)
781 sizer.Add(self.__south, 0, wxALL, 4)
782
783 ProjPanel._DoLayout(self, sizer)
784
785 def GetProjName(self):
786 return _("Universal Transverse Mercator")
787
788 def SetProjection(self, proj):
789 self.__zone.SetValue(int(proj.GetParameter("zone")))
790 self.__south.SetValue(proj.GetParameter("south") != "")
791 ProjPanel.SetProjection(self, proj)
792
793 def GetParameters(self):
794 params = ["proj=utm", "zone=" + str(self.__zone.GetValue())]
795 if self.__south.IsChecked():
796 params.append("south")
797
798 params.extend(ProjPanel.GetParameters(self))
799 return params
800
801 def Clear(self):
802 self.__zone.SetValue(1)
803 self.__south.SetValue(False)
804 ProjPanel.Clear(self)
805
806 def _OnPropose(self, event):
807 """Call the propose dialog.
808 If the receiver (e.g. the current map) has no bounding box,
809 inform the user accordingly.
810 """
811 bb = self.receiver.BoundingBox()
812 if bb is None:
813 dlg = wxMessageDialog(self,
814 _("Can not propose: No bounding box found."),
815 _("Projection: Propose UTM Zone"),
816 wxOK | wxICON_INFORMATION)
817 dlg.CenterOnParent()
818 result = dlg.ShowModal()
819 dlg.Destroy()
820 return
821
822 dlg = UTMProposeZoneDialog(self, self.receiver.BoundingBox())
823 if dlg.ShowModal() == wxID_OK:
824 self.__zone.SetValue(dlg.GetProposedZone())
825
826 class LCCPanel(ProjPanel):
827 """Projection Panel for Lambert Conic Conformal."""
828
829 def __init__(self, parent, receiver):
830 ProjPanel.__init__(self, parent)
831
832 self.__fspLatitude = wxTextCtrl(self, -1)
833 self.__sspLatitude = wxTextCtrl(self, -1)
834 self.__meridian = wxTextCtrl(self, -1)
835 self.__originLat = wxTextCtrl(self, -1)
836 self.__falseEast = wxTextCtrl(self, -1)
837 self.__falseNorth = wxTextCtrl(self, -1)
838
839 self._DoLayout()
840
841 def _DoLayout(self):
842
843 sizer = wxFlexGridSizer(6, 2, 0, 0)
844 sizer.Add(wxStaticText(self, -1,
845 _("Latitude of first standard parallel:")))
846 sizer.Add(self.__fspLatitude, 0, wxALL, 4)
847 sizer.Add(wxStaticText(self, -1,
848 _("Latitude of second standard parallel:")))
849 sizer.Add(self.__sspLatitude, 0, wxALL, 4)
850 sizer.Add(wxStaticText(self, -1, _("Central Meridian:")))
851 sizer.Add(self.__meridian, 0, wxALL, 4)
852 sizer.Add(wxStaticText(self, -1, _("Latitude of origin:")))
853 sizer.Add(self.__originLat, 0, wxALL, 4)
854 sizer.Add(wxStaticText(self, -1, _("False Easting:")))
855 sizer.Add(self.__falseEast, 0, wxALL, 4)
856 sizer.Add(wxStaticText(self, -1, _("False Northing:")))
857 sizer.Add(self.__falseNorth, 0, wxALL, 4)
858
859 ProjPanel._DoLayout(self, sizer)
860
861 def GetProjName(self):
862 return _("Lambert Conic Conformal")
863
864 def SetProjection(self, proj):
865 self.__fspLatitude.SetValue(proj.GetParameter("lat_1"))
866 self.__sspLatitude.SetValue(proj.GetParameter("lat_2"))
867 self.__originLat.SetValue(proj.GetParameter("lat_0"))
868 self.__meridian.SetValue(proj.GetParameter("lon_0"))
869 self.__falseEast.SetValue(proj.GetParameter("x_0"))
870 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
871
872 ProjPanel.SetProjection(self, proj)
873
874 def GetParameters(self):
875 params = ["proj=lcc",
876 "lat_1=" + self.__fspLatitude.GetValue(),
877 "lat_2=" + self.__sspLatitude.GetValue(),
878 "lat_0=" + self.__originLat.GetValue(),
879 "lon_0=" + self.__meridian.GetValue(),
880 "x_0=" + self.__falseEast.GetValue(),
881 "y_0=" + self.__falseNorth.GetValue()]
882
883 params.extend(ProjPanel.GetParameters(self))
884 return params
885
886 def Clear(self):
887 self.__fspLatitude.Clear()
888 self.__sspLatitude.Clear()
889 self.__originLat.Clear()
890 self.__meridian.Clear()
891 self.__falseEast.Clear()
892 self.__falseNorth.Clear()
893
894 ProjPanel.Clear(self)
895
896 class GeoPanel(ProjPanel):
897 """Projection Panel for a Geographic Projection."""
898
899 def __init__(self, parent, receiver):
900 ProjPanel.__init__(self, parent)
901
902 self.__choices = [(_("Degrees"), "0.017453"),
903 (_("Radians"), "1")]
904
905 self.__scale = wxChoice(self, -1)
906 for choice, value in self.__choices:
907 self.__scale.Append(choice, value)
908
909 self._DoLayout()
910
911 def GetProjName(self):
912 return _("Geographic")
913
914 def SetProjection(self, proj):
915 value = proj.GetParameter("to_meter")
916 for i in range(len(self.__choices)):
917 choice, data = self.__choices[i]
918 if value == data:
919 self.__scale.SetSelection(i)
920 ProjPanel.SetProjection(self, proj)
921
922 def GetParameters(self):
923 params = ["proj=latlong",
924 "to_meter=%s" % self.__scale.GetClientData(
925 self.__scale.GetSelection())]
926
927 params.extend(ProjPanel.GetParameters(self))
928 return params
929
930 def Clear(self):
931 ProjPanel.Clear(self)
932
933 def _DoLayout(self):
934 sizer = wxBoxSizer(wxHORIZONTAL)
935
936 sizer.Add(wxStaticText(self, -1, _("Source Data is in: ")),
937 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
938 sizer.Add(self.__scale, 1, wxEXPAND|wxALL, 4)
939
940 self.__scale.SetSelection(0)
941
942 ProjPanel._DoLayout(self, sizer)
943
944
945 ID_UTM_PROPOSE_ZONE_DIALOG_TAKE = 4001
946 ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL = 4002
947 class UTMProposeZoneDialog(wxDialog):
948
949 """Propose a sensible Zone considering the current map extent."""
950
951 def __init__(self, parent, (x, y, x2, y2)):
952 wxDialog.__init__(self, parent, -1, _("Projection: Propose UTM Zone"),
953 wxDefaultPosition, wxSize(200, 100))
954 self.parent = parent
955 x = x + 180
956 x2 = x2 + 180
957 center = (x2 - x) / 2 + x
958 self.proposedZone = int(center / 6 + 1)
959 self.dialogLayout()
960
961 def dialogLayout(self):
962 topBox = wxBoxSizer(wxVERTICAL)
963
964 textBox = wxBoxSizer(wxVERTICAL)
965 textBox.Add(wxStaticText(self, -1, _("The current map extent center "
966 "lies in UTM Zone")),
967 0, wxALIGN_CENTER|wxALL, 4)
968 textBox.Add(wxStaticText(self, -1, str(self.proposedZone)),
969 0, wxALIGN_CENTER|wxALL, 4)
970
971 topBox.Add(textBox, 1, wxEXPAND|wxALL, 4)
972
973 buttonBox = wxBoxSizer(wxHORIZONTAL)
974 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE,
975 _("Take")), 0, wxALL, 4)
976 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL,
977 _("Cancel")), 0, wxALL, 4)
978 topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
979 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE, self.OnTake)
980 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL, self.OnCancel)
981
982 self.SetAutoLayout(True)
983 self.SetSizer(topBox)
984 topBox.Fit(self)
985 topBox.SetSizeHints(self)
986
987 def OnTake(self, event):
988 self.EndModal(wxID_OK)
989
990 def OnCancel(self, event):
991 self.EndModal(wxID_CANCEL)
992
993 def GetProposedZone(self):
994 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