/[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 1933 - (hide annotations)
Tue Nov 11 16:37:53 2003 UTC (21 years, 3 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 36720 byte(s)
* Thuban/Model/resource.py (get_system_proj_file): Add a filename
parameter so that this function can be used for all proj files in
Resource/Projections
(DEFAULT_PROJ_FILE, EPSG_PROJ_FILE): New. Predefined filenames for
get_system_proj_file

* Thuban/UI/projdialog.py (ProjFrame.__init__): Instead of one
ProjFile self.__sysProjFile use a dictionary of system ProjFile
objects self._sys_proj_files
(ProjFrame.build_dialog): Adapt to the new changes in the
ProjectionList constructor. Add a check button to toggle whether
EPSG projections are shown
(ProjFrame._OnShowEPSG): New. Handler for the epsg check button
events.
(ProjFrame.load_user_proj, ProjFrame.load_system_proj): Only show
the busy cursor if the files have not yet been loaded by the
dialog.
(ProjFrame.load_system_proj): Add a parameter for the name of the
proj file. Maintain the dictionary of system projections
self._sys_proj_files

* Thuban/UI/projlist.py (ProjectionList): Merge the system_projs,
user_projs parameters into one parameter proj_files which is a
list of proj files.
(ProjectionList._subscribe_proj_files)
(ProjectionList._unsubscribe_proj_files): New. Move
subscription/unsubscription of projfile messages to separate
methods
(ProjectionList.Destroy): The unsubscribe is now done in
_unsubscribe_proj_files
(ProjectionList.update_projections): We now have a list of proj
file objects
(ProjectionList.SetProjFiles): New method to set a new list of
proj file objects

* test/test_proj.py (ProjFileReadTests.test_get_system_proj_file):
Specify explicitly which system proj file to load.

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