/[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 2051 - (hide annotations)
Wed Jan 21 17:09:15 2004 UTC (21 years, 1 month ago) by frank
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 37454 byte(s)
Make Thuban remember path selections (at least for one application run).

* Thuban/UI/application.py (Application.OnInit): Initialize path as a
	attribute of application object. Path is a dictionary of
	strings, currently with the items "data" and "projection".
	(Application.SetPath): New, stores path for the specified item.
	(Application.Path): New, return path for the specified item.

* Thuban/UI/mainwindow.py
	(MainWindow.OpenSession, MainWindow.SaveSessionAs,
	MainWindow.AddLayer, MainWindow.AddRasterLayer,
	MainWindow.TableOpen): Access "data" path information of the
	application.

* Thuban/UI/projdialog.py (ProjFrame._OnImport, ProjFrame._OnExport):
	Access "projection" path information of the application.

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