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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1851 - (hide annotations)
Tue Oct 21 14:17:24 2003 UTC (21 years, 4 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 34295 byte(s)
Rework the projection dialog to fix a few bugs, including RT 2166
and most of 2168

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

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26