/[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 1861 - (show annotations)
Fri Oct 24 16:03:03 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: 35165 byte(s)
(ProjFrame.__init__): Added 'longlat' as alias for 'latlong'.

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