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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2470 - (show annotations)
Thu Dec 16 11:00:10 2004 UTC (20 years, 2 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 37665 byte(s)
Fix for RT#2237

(ProjFrame._show_proj_panel): If the
panel to be shown is the UnknownProjPanel disable the OK and Try
buttons.  Otherwise enable them.
(ProjFrame.__GetProjection): The UnknownProjPanel returns None for
the parameters.  In that case __GetProjection also returns None
now.

1 # Copyright (c) 2003, 2004 by Intevation GmbH
2 # Authors:
3 # Jonathan Coles <[email protected]>
4 # Frank Koormann <[email protected]>
5 # Jan-Oliver Wagner <[email protected]>
6 #
7 # This program is free software under the GPL (>=v2)
8 # Read the file COPYING coming with Thuban for details.
9
10 """Projection dialog"""
11
12 __version__ = "$Revision$"
13 # $Source$
14 # $Id$
15
16 import os
17 from wxPython.wx import *
18
19 from Thuban import _
20
21 from Thuban.Model.proj import Projection, ProjFile
22
23 from Thuban.Model.resource import get_user_proj_file, get_system_proj_file, \
24 read_proj_file, write_proj_file, \
25 DEFAULT_PROJ_FILE, EPSG_PROJ_FILE, \
26 EPSG_DEPRECATED_PROJ_FILE
27 from Thuban.UI.dialogs import NonModalNonParentDialog
28
29 from common import ThubanBeginBusyCursor, ThubanEndBusyCursor
30 from sizers import NotebookLikeSizer
31 from projlist import PROJ_SELECTION_CHANGED, ProjectionList
32 from common import ThubanBeginBusyCursor, ThubanEndBusyCursor
33
34
35
36 ID_PROJ_PROJCHOICE = 4002
37 ID_PROJ_ADDTOLIST = 4003
38 ID_PROJ_NEW = 4004
39 ID_PROJ_REVERT = 4006
40 ID_PROJ_AVAIL = 4009
41 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
47 CLIENT_PROJ = 0
48 CLIENT_PROJFILE = 1
49
50 class ProjFrame(NonModalNonParentDialog):
51
52 def __init__(self, parent, name, title, receiver):
53 """Initialize the projection dialog.
54
55 receiver -- An object that implements the following methods:
56 SetProjection(projection)
57 GetProjection()
58 """
59 NonModalNonParentDialog.__init__(self, parent, name, title)
60
61 self.projection_panel_defs = [
62 ("tmerc", _("Transverse Mercator"), TMPanel),
63 ("utm", _("Universal Transverse Mercator"), UTMPanel),
64 ("lcc", _("Lambert Conic Conformal"), LCCPanel),
65 ("latlong", _("Geographic"), GeoPanel),
66 ("longlat", _("Geographic"), GeoPanel)]#longlat is an alias of proj
67 self.receiver = receiver
68 self.haveTried = False
69 self.curProjPanel = None
70 self.__usrProjFile = None
71 self._sys_proj_files = {}
72
73 self.build_dialog()
74 self.Layout()
75
76 self.originalProjection = self.receiver.GetProjection()
77
78 self.projection_list.SelectProjection(self.originalProjection)
79 self.projection_list.SetFocus()
80
81 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 main_box.Add(vbox, 4, wxALL|wxEXPAND)
93
94 #label = wxStaticText(self, -1, _("Available Projections:"))
95 #vbox.Add(label, 0, wxLEFT|wxRIGHT|wxTOP, 4)
96
97 hbox = wxBoxSizer(wxHORIZONTAL)
98 vbox.Add(hbox, 1, wxALL|wxEXPAND)
99 proj_files = [self.load_user_proj(),
100 self.load_system_proj(DEFAULT_PROJ_FILE)]
101 self.projection_list = ProjectionList(self, proj_files,
102 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
107 # 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
121 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 EVT_CHECKBOX(self, self.check_epsg.GetId(), self._OnShowEPSG)
126 buttons.Add(self.check_epsg, 1, wxALL|wxEXPAND, 4)
127 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
131 # The file path
132 self.projfilepath = wxStaticText(self, -1, "")
133 vbox.Add(self.projfilepath, 0, wxALL|wxEXPAND)
134
135 #
136 # The projection editor part
137 #
138 self.edit_box = wxStaticBox(self, -1, _("Edit"))
139 sizer_edit = wxStaticBoxSizer(self.edit_box, wxHORIZONTAL)
140 main_box.Add(sizer_edit, 5, wxALL|wxEXPAND)
141
142 # Projection Specific Entries (Name/Projection)
143 self.sizer_projctrls = wxBoxSizer(wxVERTICAL)
144 sizer_edit.Add(self.sizer_projctrls, 1, wxALL|wxEXPAND)
145
146 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
154 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 # Fill the projection choice list.
163 self.nbsizer = NotebookLikeSizer()
164 self.sizer_projctrls.Add(self.nbsizer, 1,
165 wxALL|wxEXPAND|wxADJUST_MINSIZE, 3)
166 self.projection_panels = []
167 self.projchoice.Append(_("<Unknown>"), "")
168 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
180 # 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
194 #
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 EVT_BUTTON(self, wxID_APPLY, self.OnApply)
201 buttons.Add(self.button_try, 0, wxRIGHT, 10)
202 self.button_revert = wxButton(self, ID_PROJ_REVERT, _("Revert"))
203 EVT_BUTTON(self, ID_PROJ_REVERT, self._OnRevert)
204 buttons.Add(self.button_revert, 0, wxRIGHT, 10)
205 self.button_ok = wxButton(self, wxID_OK, _("OK"))
206 EVT_BUTTON(self, wxID_OK, self.OnOK)
207 self.button_ok.SetDefault()
208 buttons.Add(self.button_ok, 0, wxRIGHT, 10)
209 self.button_close = wxButton(self, wxID_CANCEL, _("Close"))
210 EVT_BUTTON(self, wxID_CANCEL, self.OnCancel)
211 buttons.Add(self.button_close, 0, wxRIGHT, 10)
212
213
214 #
215 # Automatic Layout
216 #
217 self.SetAutoLayout(1)
218 self.SetSizer(top_box)
219 top_box.Fit(self)
220 top_box.SetSizeHints(self)
221
222 def OnClose(self, event):
223 self.projection_list.Unsubscribe(PROJ_SELECTION_CHANGED,
224 self.proj_selection_changed)
225 # 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 NonModalNonParentDialog.OnClose(self, event)
231
232 def OnApply(self, event):
233 self.__SetProjection()
234 self.haveTried = True
235
236 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 def _OnRevert(self, event):
247 if self.haveTried:
248 self.receiver.SetProjection(self.originalProjection)
249 self.haveTried = False
250
251 def _OnNew(self, event):
252
253 self.projection_list.ClearSelection()
254 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 if self.curProjPanel is not None:
262 self.curProjPanel.Clear()
263
264 def _OnSave(self, event):
265
266 sel = self.projection_list.selected_projections()
267 assert len(sel) == 1, "button shouldn't be enabled"
268
269 proj, projfile = sel[0]
270
271 assert proj is not None and projfile is not None
272
273 newproj = self.__GetProjection()
274
275 if newproj is not None:
276 # FIXME: we should only allow this for the user proj file.
277 projfile.Replace(proj, newproj)
278 self.write_proj_file(projfile)
279 self.projection_list.SelectProjection(newproj)
280
281 def _OnAddToList(self, event):
282
283 proj = self.__GetProjection()
284 if proj is not None:
285 self.__usrProjFile.Add(proj)
286 self.write_proj_file(self.__usrProjFile)
287 self.projection_list.SelectProjection(proj)
288
289 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 def _OnImport(self, event):
300 """Handler for the 'Import' button
301
302 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 dlg = wxFileDialog(self, _("Import"),
307 self.parent.application.Path("projection"), style = wxOPEN)
308
309 if dlg.ShowModal() == wxID_OK:
310 path = dlg.GetPath()
311
312 ThubanBeginBusyCursor()
313 try:
314 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 self.parent.application.SetPath("projection", path)
324 finally:
325 ThubanEndBusyCursor()
326 dlg.Destroy()
327
328 def _OnExport(self, event):
329 """Handler for the 'Export' button.
330
331 Ask the user for a filename and write the selected projections
332 to that file.
333 """
334 sel = self.projection_list.selected_projections()
335 assert len(sel) != 0, "button should be disabled"
336
337 dlg = wxFileDialog(self, _("Export"),
338 self.parent.application.Path("projection"),
339 style=wxSAVE|wxOVERWRITE_PROMPT)
340
341 if dlg.ShowModal() == wxID_OK:
342 proj_file = ProjFile(dlg.GetPath())
343 for proj, pf in sel:
344 if proj is not None:
345 proj_file.Add(proj)
346 self.write_proj_file(proj_file)
347 self.parent.application.SetPath("projection", dlg.GetPath())
348
349 dlg.Destroy()
350
351 def _OnRemove(self, event):
352 """Handler for the 'Remove' button
353
354 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 assert len(sel) != 0, "button should be disabled!"
360
361 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
367 if modified:
368 self.write_proj_file(self.__usrProjFile)
369
370 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 proj_files = [self.load_user_proj(),
377 self.load_system_proj(DEFAULT_PROJ_FILE)]
378 if self.check_epsg.IsChecked():
379 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 self.projection_list.SetProjFiles(proj_files)
383
384 def _OnProjName(self, event):
385 self.__VerifyButtons()
386
387 def __ShowError(self, filename, errstr):
388 wxMessageDialog(self,
389 _("The following error occured:\n") +
390 filename + "\n" + errstr,
391 _("Error"), wxOK | wxICON_ERROR).ShowModal()
392
393 def __VerifyButtons(self):
394 """Update button sensitivity"""
395
396 num_sel = self.projection_list.GetSelectedItemCount()
397
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 self.edit_box.Enable(True)
404
405 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 self.edit_box]:
413 ctrl.Enable(True)
414
415 if self.curProjPanel is not None:
416 self.curProjPanel.Enable(True)
417
418 if num_sel == 0:
419 self.button_import.Enable(True)
420 self.button_export.Enable(False)
421 self.button_remove.Enable(False)
422 self.button_save.Enable(False)
423
424 elif num_sel == 1:
425
426 selection = self.projection_list.selected_projections()
427 proj, projFile = selection[0]
428
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 # <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 self.button_remove.Enable(False)
447
448 if projFile is None:
449 self.button_save.Enable(False)
450
451 else:
452 self.edit_box.Enable(False)
453
454 def proj_selection_changed(self, projs):
455 """Subscribed to the projection_list's PROJ_SELECTION_CHANGED message
456
457 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 if proj is None:
464 # user selected <None>
465 self.projname.Clear()
466 self.projfilepath.SetLabel("")
467 else:
468 if projfile is not None:
469 filename = os.path.basename(projfile.GetFilename())
470 self.projfilepath.SetLabel(_("Source of Projection: %s")
471 % filename)
472 else:
473 # only None if the currently used projection is selected
474 self.projfilepath.SetLabel("")
475
476 self.projname.SetValue(proj.Label())
477
478 myProjType = proj.GetParameter("proj")
479 i = 0
480 for projType, name, cls in self.projection_panel_defs:
481 if myProjType == projType:
482 self.projchoice.Enable(True)
483 self.projchoice.SetSelection(i + 1)
484 self.__DoOnProjChoice()
485
486 #
487 # self.curProjPanel should not be null
488 # after a call to __DoOnProjChoice
489 #
490 assert self.curProjPanel is not None
491
492 self.curProjPanel.SetProjection(proj)
493 break
494 i += 1
495 else:
496 self.projchoice.Select(0)
497 self.projchoice.Disable()
498 self._show_proj_panel(UnknownProjPanel)
499 assert self.curProjPanel is not None
500 self.curProjPanel.SetProjection(proj)
501 else:
502 self.projfilepath.SetLabel(_("Multiple Projections selected"))
503
504 self.__VerifyButtons()
505
506 def _OnProjChoice(self, event):
507 self.__DoOnProjChoice()
508
509 def __DoOnProjChoice(self):
510 """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 choice = self.projchoice
520
521 sel = choice.GetSelection()
522 if sel != -1:
523 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
530 def _show_proj_panel(self, panel_class):
531 """Show the panel as the projection panel"""
532 if panel_class is UnknownProjPanel:
533 self.button_ok.Disable()
534 self.button_try.Disable()
535 self.edit_box.Disable()
536 self.nbsizer.Activate(self.unknown_projection_panel)
537 self.curProjPanel = self.unknown_projection_panel
538 else:
539 self.button_ok.Enable(True)
540 self.button_try.Enable(True)
541 self.edit_box.Enable(True)
542 self.unknown_projection_panel.Hide()
543 for panel in self.projection_panels:
544 if panel.__class__ is panel_class:
545 self.nbsizer.Activate(panel)
546 self.curProjPanel = panel
547
548 def __SetProjection(self):
549 """Set the receiver's projection."""
550
551 #
552 # save the original projection only once in case
553 # we try to apply several different projections
554 #
555 self.receiver.SetProjection(self.__GetProjection())
556
557 def __GetProjection(self):
558 """Return a suitable Projection object based on the current
559 state of the dialog box selections.
560
561 Could be None.
562 """
563
564 assert self.projection_list.GetSelectedItemCount() < 2, \
565 "button should be disabled"
566
567 sel = self.projection_list.selected_projections()
568 if len(sel) == 1:
569 if sel[0][0] is None:
570 # <None> is selected
571 return None
572
573 # self.curProjPanel should always contain the most relevant data
574 # for a projection
575 if self.curProjPanel is not None:
576 parameters = self.curProjPanel.GetParameters()
577 if parameters is not None:
578 return Projection(parameters, self.projname.GetValue())
579
580 return None
581
582 def load_user_proj(self):
583 """Return the user's ProjFile
584
585 If the file has not yet been loaded by the dialog, load it first
586 with get_user_proj_file and cache it in self.__usrProjFile.
587
588 Show a busy cursor while loading the file.
589
590 If the file is not available, leave a note to the console.
591 """
592 if self.__usrProjFile is None:
593 ThubanBeginBusyCursor()
594 try:
595 projfile, warnings = get_user_proj_file()
596 if warnings:
597 sys.stderr.write("".join(warnings))
598 self.__usrProjFile = projfile
599 finally:
600 ThubanEndBusyCursor()
601 return self.__usrProjFile
602
603 def load_system_proj(self, name):
604 """Load the system ProjFile with the given name.
605
606 If the file has not been loaded yet, load it first with
607 get_system_proj_file and put it into the cache. The name is
608 simply forwarded to get_system_proj_file.
609
610 Show a busy cursor while loading the file.
611 """
612 if name not in self._sys_proj_files:
613 ThubanBeginBusyCursor()
614 try:
615 projfile, warnings = get_system_proj_file(name)
616 self.show_warnings(_("Warnings"), projfile.GetFilename(),
617 warnings)
618 self._sys_proj_files[name] = projfile
619 finally:
620 ThubanEndBusyCursor()
621 return self._sys_proj_files[name]
622
623 def write_proj_file(self, proj_file):
624 """Write the ProjFile object proj_file back to its file
625
626 Show a busy cursor while writing and if an error occurs show a
627 dialog with the error message.
628 """
629 try:
630 ThubanBeginBusyCursor()
631 try:
632 write_proj_file(proj_file)
633 finally:
634 ThubanEndBusyCursor()
635 except IOError, (errno, errstr):
636 self.__ShowError(proj_file.GetFilename(), errstr)
637
638
639
640 class ProjPanel(wxPanel):
641 """Base class for all projection panels."""
642
643 def __init__(self, parent):
644 wxPanel.__init__(self, parent, -1)
645
646 self.__ellps = wxChoice(self, -1)
647 self.ellpsData = [("", _("<Unknown>")),
648 ("airy" , _("Airy")),
649 ("bessel", _("Bessel 1841")),
650 ("clrk66", _("Clarke 1866")),
651 ("clrk80", _("Clarke 1880")),
652 ("GRS80" , _("GRS 1980 (IUGG, 1980)")),
653 ("intl" , _("International 1909 (Hayford)")),
654 ("WGS84" , _("WGS 84"))]
655
656 for tag, name in self.ellpsData:
657 self.__ellps.Append(name, tag)
658
659 self.__ellps.SetSelection(0)
660
661 def _DoLayout(self, childPanel = None):
662
663 panelSizer = wxBoxSizer(wxVERTICAL)
664
665 sizer = wxBoxSizer(wxHORIZONTAL)
666 sizer.Add(wxStaticText(self, -1, _("Ellipsoid:")), 0,
667 wxALL|wxALIGN_CENTER_VERTICAL, 4)
668 sizer.Add(self.__ellps, 1, wxALL|wxALIGN_CENTER_VERTICAL, 4)
669 panelSizer.Add(sizer, 0, wxALL|wxEXPAND, 4)
670
671 if childPanel is not None:
672 panelSizer.Add(childPanel, 0, wxEXPAND, 0)
673
674 self.SetAutoLayout(1)
675 self.SetSizer(panelSizer)
676 panelSizer.Fit(self)
677 panelSizer.SetSizeHints(self)
678 self.Layout()
679
680 def SetProjection(self, proj):
681 if proj is not None:
682 param = proj.GetParameter("ellps")
683 i = 0
684 for tag, name in self.ellpsData:
685 if param == tag:
686 self.__ellps.SetSelection(i)
687 return # returning early!
688 i += 1
689
690 #
691 # if proj is none, or the parameter couldn't be found...
692 #
693 self.__ellps.SetSelection(0)
694
695 def GetParameters(self):
696 ellps = self.__ellps.GetSelection()
697 if ellps > 0:
698 return ["ellps=" + self.__ellps.GetClientData(ellps)]
699 return []
700
701
702 ID_TMPANEL_LAT = 4001
703 ID_TMPANEL_LONG = 4002
704 ID_TMPANEL_FASLE_EAST = 4003
705 ID_TMPANEL_FALSE_NORTH = 4004
706 ID_TMPANEL_SCALE = 4005
707
708 class UnknownProjPanel(ProjPanel):
709
710 """Panel for unknown projection types"""
711
712 def __init__(self, parent, receiver):
713 ProjPanel.__init__(self, parent)
714
715 self.__text = _("Thuban does not know the parameters\n"
716 "for the current projection and cannot\n"
717 "display a configuration panel.\n\n"
718 "The unidentified set of parameters is:\n\n")
719
720 self.__textbox = wxTextCtrl(self, -1, self.__text, size=(100,200),
721 style=wxTE_READONLY|wxTE_MULTILINE|wxTE_LINEWRAP)
722 self._DoLayout()
723
724 def _DoLayout(self):
725 sizer = wxBoxSizer(wxVERTICAL)
726
727 sizer.Add(self.__textbox, 0, wxALL|wxEXPAND, 4)
728
729 ProjPanel._DoLayout(self, sizer)
730
731 def GetProjName(self):
732 return "Unknown"
733
734 def SetProjection(self, proj):
735 """Append the available parameters to the info text."""
736 text = self.__text
737 for param in proj.GetAllParameters():
738 text = text + '%s\n' % param
739 self.__textbox.SetValue(text)
740
741 def GetParameters(self):
742 return None
743
744 class TMPanel(ProjPanel):
745 """Projection panel for Transverse Mercator."""
746
747 def __init__(self, parent, receiver):
748 ProjPanel.__init__(self, parent)
749
750 self.__latitude = wxTextCtrl(self, ID_TMPANEL_LAT)
751 self.__longitude = wxTextCtrl(self, ID_TMPANEL_LONG)
752 self.__falseEast = wxTextCtrl(self, ID_TMPANEL_FASLE_EAST)
753 self.__falseNorth = wxTextCtrl(self, ID_TMPANEL_FALSE_NORTH)
754 self.__scale = wxTextCtrl(self, ID_TMPANEL_SCALE)
755
756 self._DoLayout()
757
758 def _DoLayout(self):
759
760 sizer = wxFlexGridSizer(4, 2, 0, 0)
761 sizer.Add(wxStaticText(self, -1, _("Latitude:")), 0, wxALL, 4)
762 sizer.Add(self.__latitude, 0, wxALL, 4)
763 sizer.Add(wxStaticText(self, -1, _("Longitude:")), 0, wxALL, 4)
764 sizer.Add(self.__longitude, 0, wxALL, 4)
765 sizer.Add(wxStaticText(self, -1, _("False Easting:")), 0, wxALL, 4)
766 sizer.Add(self.__falseEast, 0, wxALL, 4)
767 sizer.Add(wxStaticText(self, -1, _("False Northing:")), 0, wxALL, 4)
768 sizer.Add(self.__falseNorth, 0, wxALL, 4)
769 sizer.Add(wxStaticText(self, -1, _("Scale Factor:")), 0, wxALL, 4)
770 sizer.Add(self.__scale, 0, wxALL, 4)
771
772 ProjPanel._DoLayout(self, sizer)
773
774 def GetProjName(self):
775 return _("Transverse Mercator")
776
777 def SetProjection(self, proj):
778 ProjPanel.SetProjection(self, proj)
779
780 self.__latitude.SetValue(proj.GetParameter("lat_0"))
781 self.__longitude.SetValue(proj.GetParameter("lon_0"))
782 self.__falseEast.SetValue(proj.GetParameter("x_0"))
783 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
784 self.__scale.SetValue(proj.GetParameter("k"))
785
786 ProjPanel.SetProjection(self, proj)
787
788 def GetParameters(self):
789 params = ["proj=tmerc",
790 "lat_0=" + self.__latitude.GetValue(),
791 "lon_0=" + self.__longitude.GetValue(),
792 "x_0=" + self.__falseEast.GetValue(),
793 "y_0=" + self.__falseNorth.GetValue(),
794 "k=" + self.__scale.GetValue()]
795 params.extend(ProjPanel.GetParameters(self))
796 return params
797
798 def Clear(self):
799 self.__latitude.Clear()
800 self.__longitude.Clear()
801 self.__falseEast.Clear()
802 self.__falseNorth.Clear()
803 self.__scale.Clear()
804
805 ProjPanel.Clear(self)
806
807 ID_UTMPANEL_ZONE = 4001
808 ID_UTMPANEL_SOUTH = 4002
809 ID_UTMPANEL_PROP = 4003
810
811 class UTMPanel(ProjPanel):
812 """Projection Panel for Universal Transverse Mercator."""
813
814 def __init__(self, parent, receiver):
815 ProjPanel.__init__(self, parent)
816
817 self.receiver = receiver
818
819 self.__zone = wxSpinCtrl(self, ID_UTMPANEL_ZONE, "1", min=1, max=60)
820 self.__propButton = wxButton(self, ID_UTMPANEL_PROP, _("Propose"))
821 self.__south = wxCheckBox(self, ID_UTMPANEL_SOUTH,
822 _("Southern Hemisphere"))
823
824 self._DoLayout()
825
826 EVT_BUTTON(self, ID_UTMPANEL_PROP, self._OnPropose)
827
828 def _DoLayout(self):
829
830 sizer = wxBoxSizer(wxVERTICAL)
831 psizer = wxBoxSizer(wxHORIZONTAL)
832 psizer.Add(wxStaticText(self, -1, _("Zone:")), 0, wxALL, 4)
833 psizer.Add(self.__zone, 0, wxALL, 4)
834 psizer.Add(self.__propButton, 0, wxALL, 4)
835 sizer.Add(psizer, 0, wxALL, 4)
836 sizer.Add(self.__south, 0, wxALL, 4)
837
838 ProjPanel._DoLayout(self, sizer)
839
840 def GetProjName(self):
841 return _("Universal Transverse Mercator")
842
843 def SetProjection(self, proj):
844 self.__zone.SetValue(int(proj.GetParameter("zone")))
845 self.__south.SetValue(proj.GetParameter("south") != "")
846 ProjPanel.SetProjection(self, proj)
847
848 def GetParameters(self):
849 params = ["proj=utm", "zone=" + str(self.__zone.GetValue())]
850 if self.__south.IsChecked():
851 params.append("south")
852
853 params.extend(ProjPanel.GetParameters(self))
854 return params
855
856 def Clear(self):
857 self.__zone.SetValue(1)
858 self.__south.SetValue(False)
859 ProjPanel.Clear(self)
860
861 def _OnPropose(self, event):
862 """Call the propose dialog.
863 If the receiver (e.g. the current map) has no bounding box,
864 inform the user accordingly.
865 """
866 bb = self.receiver.BoundingBox()
867 if bb is None:
868 dlg = wxMessageDialog(self,
869 _("Can not propose: No bounding box found."),
870 _("Projection: Propose UTM Zone"),
871 wxOK | wxICON_INFORMATION)
872 dlg.CenterOnParent()
873 result = dlg.ShowModal()
874 dlg.Destroy()
875 return
876
877 dlg = UTMProposeZoneDialog(self, self.receiver.BoundingBox())
878 if dlg.ShowModal() == wxID_OK:
879 self.__zone.SetValue(dlg.GetProposedZone())
880
881 class LCCPanel(ProjPanel):
882 """Projection Panel for Lambert Conic Conformal."""
883
884 def __init__(self, parent, receiver):
885 ProjPanel.__init__(self, parent)
886
887 self.__fspLatitude = wxTextCtrl(self, -1)
888 self.__sspLatitude = wxTextCtrl(self, -1)
889 self.__meridian = wxTextCtrl(self, -1)
890 self.__originLat = wxTextCtrl(self, -1)
891 self.__falseEast = wxTextCtrl(self, -1)
892 self.__falseNorth = wxTextCtrl(self, -1)
893
894 self._DoLayout()
895
896 def _DoLayout(self):
897
898 sizer = wxFlexGridSizer(6, 2, 0, 0)
899 sizer.Add(wxStaticText(self, -1,
900 _("Latitude of first standard parallel:")))
901 sizer.Add(self.__fspLatitude, 0, wxALL, 4)
902 sizer.Add(wxStaticText(self, -1,
903 _("Latitude of second standard parallel:")))
904 sizer.Add(self.__sspLatitude, 0, wxALL, 4)
905 sizer.Add(wxStaticText(self, -1, _("Central Meridian:")))
906 sizer.Add(self.__meridian, 0, wxALL, 4)
907 sizer.Add(wxStaticText(self, -1, _("Latitude of origin:")))
908 sizer.Add(self.__originLat, 0, wxALL, 4)
909 sizer.Add(wxStaticText(self, -1, _("False Easting:")))
910 sizer.Add(self.__falseEast, 0, wxALL, 4)
911 sizer.Add(wxStaticText(self, -1, _("False Northing:")))
912 sizer.Add(self.__falseNorth, 0, wxALL, 4)
913
914 ProjPanel._DoLayout(self, sizer)
915
916 def GetProjName(self):
917 return _("Lambert Conic Conformal")
918
919 def SetProjection(self, proj):
920 self.__fspLatitude.SetValue(proj.GetParameter("lat_1"))
921 self.__sspLatitude.SetValue(proj.GetParameter("lat_2"))
922 self.__originLat.SetValue(proj.GetParameter("lat_0"))
923 self.__meridian.SetValue(proj.GetParameter("lon_0"))
924 self.__falseEast.SetValue(proj.GetParameter("x_0"))
925 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
926
927 ProjPanel.SetProjection(self, proj)
928
929 def GetParameters(self):
930 params = ["proj=lcc",
931 "lat_1=" + self.__fspLatitude.GetValue(),
932 "lat_2=" + self.__sspLatitude.GetValue(),
933 "lat_0=" + self.__originLat.GetValue(),
934 "lon_0=" + self.__meridian.GetValue(),
935 "x_0=" + self.__falseEast.GetValue(),
936 "y_0=" + self.__falseNorth.GetValue()]
937
938 params.extend(ProjPanel.GetParameters(self))
939 return params
940
941 def Clear(self):
942 self.__fspLatitude.Clear()
943 self.__sspLatitude.Clear()
944 self.__originLat.Clear()
945 self.__meridian.Clear()
946 self.__falseEast.Clear()
947 self.__falseNorth.Clear()
948
949 ProjPanel.Clear(self)
950
951 class GeoPanel(ProjPanel):
952 """Projection Panel for a Geographic Projection."""
953
954 def __init__(self, parent, receiver):
955 ProjPanel.__init__(self, parent)
956
957 self.__choices = [(_("Degrees"), "0.017453"),
958 (_("Radians"), "1")]
959
960 self.__scale = wxChoice(self, -1)
961 for choice, value in self.__choices:
962 self.__scale.Append(choice, value)
963
964 self._DoLayout()
965
966 def GetProjName(self):
967 return _("Geographic")
968
969 def SetProjection(self, proj):
970 value = proj.GetParameter("to_meter")
971 for i in range(len(self.__choices)):
972 choice, data = self.__choices[i]
973 if value == data:
974 self.__scale.SetSelection(i)
975 ProjPanel.SetProjection(self, proj)
976
977 def GetParameters(self):
978 params = ["proj=latlong",
979 "to_meter=%s" % self.__scale.GetClientData(
980 self.__scale.GetSelection())]
981
982 params.extend(ProjPanel.GetParameters(self))
983 return params
984
985 def Clear(self):
986 ProjPanel.Clear(self)
987
988 def _DoLayout(self):
989 sizer = wxBoxSizer(wxHORIZONTAL)
990
991 sizer.Add(wxStaticText(self, -1, _("Source Data is in: ")),
992 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
993 sizer.Add(self.__scale, 1, wxEXPAND|wxALL, 4)
994
995 self.__scale.SetSelection(0)
996
997 ProjPanel._DoLayout(self, sizer)
998
999
1000 ID_UTM_PROPOSE_ZONE_DIALOG_TAKE = 4001
1001 ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL = 4002
1002 class UTMProposeZoneDialog(wxDialog):
1003
1004 """Propose a sensible Zone considering the current map extent."""
1005
1006 def __init__(self, parent, (x, y, x2, y2)):
1007 wxDialog.__init__(self, parent, -1, _("Projection: Propose UTM Zone"),
1008 wxDefaultPosition, wxSize(200, 100))
1009 self.parent = parent
1010 x = x + 180
1011 x2 = x2 + 180
1012 center = (x2 - x) / 2 + x
1013 self.proposedZone = int(center / 6 + 1)
1014 self.dialogLayout()
1015
1016 def dialogLayout(self):
1017 topBox = wxBoxSizer(wxVERTICAL)
1018
1019 textBox = wxBoxSizer(wxVERTICAL)
1020 textBox.Add(wxStaticText(self, -1, _("The current map extent center "
1021 "lies in UTM Zone")),
1022 0, wxALIGN_CENTER|wxALL, 4)
1023 textBox.Add(wxStaticText(self, -1, str(self.proposedZone)),
1024 0, wxALIGN_CENTER|wxALL, 4)
1025
1026 topBox.Add(textBox, 1, wxEXPAND|wxALL, 4)
1027
1028 buttonBox = wxBoxSizer(wxHORIZONTAL)
1029 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE,
1030 _("Take")), 0, wxALL, 4)
1031 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL,
1032 _("Cancel")), 0, wxALL, 4)
1033 topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
1034 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE, self.OnTake)
1035 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL, self.OnCancel)
1036
1037 self.SetAutoLayout(True)
1038 self.SetSizer(topBox)
1039 topBox.Fit(self)
1040 topBox.SetSizeHints(self)
1041
1042 def OnTake(self, event):
1043 self.EndModal(wxID_OK)
1044
1045 def OnCancel(self, event):
1046 self.EndModal(wxID_CANCEL)
1047
1048 def GetProposedZone(self):
1049 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