/[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 2505 - (show annotations)
Thu Dec 23 15:10:41 2004 UTC (20 years, 2 months ago) by jan
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 37704 byte(s)
(ProjFrame.load_user_proj): Added a
\n to stderr after the warnings. Thanks to Russell Nelson.

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 sys.stderr.write("\n")
599 self.__usrProjFile = projfile
600 finally:
601 ThubanEndBusyCursor()
602 return self.__usrProjFile
603
604 def load_system_proj(self, name):
605 """Load the system ProjFile with the given name.
606
607 If the file has not been loaded yet, load it first with
608 get_system_proj_file and put it into the cache. The name is
609 simply forwarded to get_system_proj_file.
610
611 Show a busy cursor while loading the file.
612 """
613 if name not in self._sys_proj_files:
614 ThubanBeginBusyCursor()
615 try:
616 projfile, warnings = get_system_proj_file(name)
617 self.show_warnings(_("Warnings"), projfile.GetFilename(),
618 warnings)
619 self._sys_proj_files[name] = projfile
620 finally:
621 ThubanEndBusyCursor()
622 return self._sys_proj_files[name]
623
624 def write_proj_file(self, proj_file):
625 """Write the ProjFile object proj_file back to its file
626
627 Show a busy cursor while writing and if an error occurs show a
628 dialog with the error message.
629 """
630 try:
631 ThubanBeginBusyCursor()
632 try:
633 write_proj_file(proj_file)
634 finally:
635 ThubanEndBusyCursor()
636 except IOError, (errno, errstr):
637 self.__ShowError(proj_file.GetFilename(), errstr)
638
639
640
641 class ProjPanel(wxPanel):
642 """Base class for all projection panels."""
643
644 def __init__(self, parent):
645 wxPanel.__init__(self, parent, -1)
646
647 self.__ellps = wxChoice(self, -1)
648 self.ellpsData = [("", _("<Unknown>")),
649 ("airy" , _("Airy")),
650 ("bessel", _("Bessel 1841")),
651 ("clrk66", _("Clarke 1866")),
652 ("clrk80", _("Clarke 1880")),
653 ("GRS80" , _("GRS 1980 (IUGG, 1980)")),
654 ("intl" , _("International 1909 (Hayford)")),
655 ("WGS84" , _("WGS 84"))]
656
657 for tag, name in self.ellpsData:
658 self.__ellps.Append(name, tag)
659
660 self.__ellps.SetSelection(0)
661
662 def _DoLayout(self, childPanel = None):
663
664 panelSizer = wxBoxSizer(wxVERTICAL)
665
666 sizer = wxBoxSizer(wxHORIZONTAL)
667 sizer.Add(wxStaticText(self, -1, _("Ellipsoid:")), 0,
668 wxALL|wxALIGN_CENTER_VERTICAL, 4)
669 sizer.Add(self.__ellps, 1, wxALL|wxALIGN_CENTER_VERTICAL, 4)
670 panelSizer.Add(sizer, 0, wxALL|wxEXPAND, 4)
671
672 if childPanel is not None:
673 panelSizer.Add(childPanel, 0, wxEXPAND, 0)
674
675 self.SetAutoLayout(1)
676 self.SetSizer(panelSizer)
677 panelSizer.Fit(self)
678 panelSizer.SetSizeHints(self)
679 self.Layout()
680
681 def SetProjection(self, proj):
682 if proj is not None:
683 param = proj.GetParameter("ellps")
684 i = 0
685 for tag, name in self.ellpsData:
686 if param == tag:
687 self.__ellps.SetSelection(i)
688 return # returning early!
689 i += 1
690
691 #
692 # if proj is none, or the parameter couldn't be found...
693 #
694 self.__ellps.SetSelection(0)
695
696 def GetParameters(self):
697 ellps = self.__ellps.GetSelection()
698 if ellps > 0:
699 return ["ellps=" + self.__ellps.GetClientData(ellps)]
700 return []
701
702
703 ID_TMPANEL_LAT = 4001
704 ID_TMPANEL_LONG = 4002
705 ID_TMPANEL_FASLE_EAST = 4003
706 ID_TMPANEL_FALSE_NORTH = 4004
707 ID_TMPANEL_SCALE = 4005
708
709 class UnknownProjPanel(ProjPanel):
710
711 """Panel for unknown projection types"""
712
713 def __init__(self, parent, receiver):
714 ProjPanel.__init__(self, parent)
715
716 self.__text = _("Thuban does not know the parameters\n"
717 "for the current projection and cannot\n"
718 "display a configuration panel.\n\n"
719 "The unidentified set of parameters is:\n\n")
720
721 self.__textbox = wxTextCtrl(self, -1, self.__text, size=(100,200),
722 style=wxTE_READONLY|wxTE_MULTILINE|wxTE_LINEWRAP)
723 self._DoLayout()
724
725 def _DoLayout(self):
726 sizer = wxBoxSizer(wxVERTICAL)
727
728 sizer.Add(self.__textbox, 0, wxALL|wxEXPAND, 4)
729
730 ProjPanel._DoLayout(self, sizer)
731
732 def GetProjName(self):
733 return "Unknown"
734
735 def SetProjection(self, proj):
736 """Append the available parameters to the info text."""
737 text = self.__text
738 for param in proj.GetAllParameters():
739 text = text + '%s\n' % param
740 self.__textbox.SetValue(text)
741
742 def GetParameters(self):
743 return None
744
745 class TMPanel(ProjPanel):
746 """Projection panel for Transverse Mercator."""
747
748 def __init__(self, parent, receiver):
749 ProjPanel.__init__(self, parent)
750
751 self.__latitude = wxTextCtrl(self, ID_TMPANEL_LAT)
752 self.__longitude = wxTextCtrl(self, ID_TMPANEL_LONG)
753 self.__falseEast = wxTextCtrl(self, ID_TMPANEL_FASLE_EAST)
754 self.__falseNorth = wxTextCtrl(self, ID_TMPANEL_FALSE_NORTH)
755 self.__scale = wxTextCtrl(self, ID_TMPANEL_SCALE)
756
757 self._DoLayout()
758
759 def _DoLayout(self):
760
761 sizer = wxFlexGridSizer(4, 2, 0, 0)
762 sizer.Add(wxStaticText(self, -1, _("Latitude:")), 0, wxALL, 4)
763 sizer.Add(self.__latitude, 0, wxALL, 4)
764 sizer.Add(wxStaticText(self, -1, _("Longitude:")), 0, wxALL, 4)
765 sizer.Add(self.__longitude, 0, wxALL, 4)
766 sizer.Add(wxStaticText(self, -1, _("False Easting:")), 0, wxALL, 4)
767 sizer.Add(self.__falseEast, 0, wxALL, 4)
768 sizer.Add(wxStaticText(self, -1, _("False Northing:")), 0, wxALL, 4)
769 sizer.Add(self.__falseNorth, 0, wxALL, 4)
770 sizer.Add(wxStaticText(self, -1, _("Scale Factor:")), 0, wxALL, 4)
771 sizer.Add(self.__scale, 0, wxALL, 4)
772
773 ProjPanel._DoLayout(self, sizer)
774
775 def GetProjName(self):
776 return _("Transverse Mercator")
777
778 def SetProjection(self, proj):
779 ProjPanel.SetProjection(self, proj)
780
781 self.__latitude.SetValue(proj.GetParameter("lat_0"))
782 self.__longitude.SetValue(proj.GetParameter("lon_0"))
783 self.__falseEast.SetValue(proj.GetParameter("x_0"))
784 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
785 self.__scale.SetValue(proj.GetParameter("k"))
786
787 ProjPanel.SetProjection(self, proj)
788
789 def GetParameters(self):
790 params = ["proj=tmerc",
791 "lat_0=" + self.__latitude.GetValue(),
792 "lon_0=" + self.__longitude.GetValue(),
793 "x_0=" + self.__falseEast.GetValue(),
794 "y_0=" + self.__falseNorth.GetValue(),
795 "k=" + self.__scale.GetValue()]
796 params.extend(ProjPanel.GetParameters(self))
797 return params
798
799 def Clear(self):
800 self.__latitude.Clear()
801 self.__longitude.Clear()
802 self.__falseEast.Clear()
803 self.__falseNorth.Clear()
804 self.__scale.Clear()
805
806 ProjPanel.Clear(self)
807
808 ID_UTMPANEL_ZONE = 4001
809 ID_UTMPANEL_SOUTH = 4002
810 ID_UTMPANEL_PROP = 4003
811
812 class UTMPanel(ProjPanel):
813 """Projection Panel for Universal Transverse Mercator."""
814
815 def __init__(self, parent, receiver):
816 ProjPanel.__init__(self, parent)
817
818 self.receiver = receiver
819
820 self.__zone = wxSpinCtrl(self, ID_UTMPANEL_ZONE, "1", min=1, max=60)
821 self.__propButton = wxButton(self, ID_UTMPANEL_PROP, _("Propose"))
822 self.__south = wxCheckBox(self, ID_UTMPANEL_SOUTH,
823 _("Southern Hemisphere"))
824
825 self._DoLayout()
826
827 EVT_BUTTON(self, ID_UTMPANEL_PROP, self._OnPropose)
828
829 def _DoLayout(self):
830
831 sizer = wxBoxSizer(wxVERTICAL)
832 psizer = wxBoxSizer(wxHORIZONTAL)
833 psizer.Add(wxStaticText(self, -1, _("Zone:")), 0, wxALL, 4)
834 psizer.Add(self.__zone, 0, wxALL, 4)
835 psizer.Add(self.__propButton, 0, wxALL, 4)
836 sizer.Add(psizer, 0, wxALL, 4)
837 sizer.Add(self.__south, 0, wxALL, 4)
838
839 ProjPanel._DoLayout(self, sizer)
840
841 def GetProjName(self):
842 return _("Universal Transverse Mercator")
843
844 def SetProjection(self, proj):
845 self.__zone.SetValue(int(proj.GetParameter("zone")))
846 self.__south.SetValue(proj.GetParameter("south") != "")
847 ProjPanel.SetProjection(self, proj)
848
849 def GetParameters(self):
850 params = ["proj=utm", "zone=" + str(self.__zone.GetValue())]
851 if self.__south.IsChecked():
852 params.append("south")
853
854 params.extend(ProjPanel.GetParameters(self))
855 return params
856
857 def Clear(self):
858 self.__zone.SetValue(1)
859 self.__south.SetValue(False)
860 ProjPanel.Clear(self)
861
862 def _OnPropose(self, event):
863 """Call the propose dialog.
864 If the receiver (e.g. the current map) has no bounding box,
865 inform the user accordingly.
866 """
867 bb = self.receiver.BoundingBox()
868 if bb is None:
869 dlg = wxMessageDialog(self,
870 _("Can not propose: No bounding box found."),
871 _("Projection: Propose UTM Zone"),
872 wxOK | wxICON_INFORMATION)
873 dlg.CenterOnParent()
874 result = dlg.ShowModal()
875 dlg.Destroy()
876 return
877
878 dlg = UTMProposeZoneDialog(self, self.receiver.BoundingBox())
879 if dlg.ShowModal() == wxID_OK:
880 self.__zone.SetValue(dlg.GetProposedZone())
881
882 class LCCPanel(ProjPanel):
883 """Projection Panel for Lambert Conic Conformal."""
884
885 def __init__(self, parent, receiver):
886 ProjPanel.__init__(self, parent)
887
888 self.__fspLatitude = wxTextCtrl(self, -1)
889 self.__sspLatitude = wxTextCtrl(self, -1)
890 self.__meridian = wxTextCtrl(self, -1)
891 self.__originLat = wxTextCtrl(self, -1)
892 self.__falseEast = wxTextCtrl(self, -1)
893 self.__falseNorth = wxTextCtrl(self, -1)
894
895 self._DoLayout()
896
897 def _DoLayout(self):
898
899 sizer = wxFlexGridSizer(6, 2, 0, 0)
900 sizer.Add(wxStaticText(self, -1,
901 _("Latitude of first standard parallel:")))
902 sizer.Add(self.__fspLatitude, 0, wxALL, 4)
903 sizer.Add(wxStaticText(self, -1,
904 _("Latitude of second standard parallel:")))
905 sizer.Add(self.__sspLatitude, 0, wxALL, 4)
906 sizer.Add(wxStaticText(self, -1, _("Central Meridian:")))
907 sizer.Add(self.__meridian, 0, wxALL, 4)
908 sizer.Add(wxStaticText(self, -1, _("Latitude of origin:")))
909 sizer.Add(self.__originLat, 0, wxALL, 4)
910 sizer.Add(wxStaticText(self, -1, _("False Easting:")))
911 sizer.Add(self.__falseEast, 0, wxALL, 4)
912 sizer.Add(wxStaticText(self, -1, _("False Northing:")))
913 sizer.Add(self.__falseNorth, 0, wxALL, 4)
914
915 ProjPanel._DoLayout(self, sizer)
916
917 def GetProjName(self):
918 return _("Lambert Conic Conformal")
919
920 def SetProjection(self, proj):
921 self.__fspLatitude.SetValue(proj.GetParameter("lat_1"))
922 self.__sspLatitude.SetValue(proj.GetParameter("lat_2"))
923 self.__originLat.SetValue(proj.GetParameter("lat_0"))
924 self.__meridian.SetValue(proj.GetParameter("lon_0"))
925 self.__falseEast.SetValue(proj.GetParameter("x_0"))
926 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
927
928 ProjPanel.SetProjection(self, proj)
929
930 def GetParameters(self):
931 params = ["proj=lcc",
932 "lat_1=" + self.__fspLatitude.GetValue(),
933 "lat_2=" + self.__sspLatitude.GetValue(),
934 "lat_0=" + self.__originLat.GetValue(),
935 "lon_0=" + self.__meridian.GetValue(),
936 "x_0=" + self.__falseEast.GetValue(),
937 "y_0=" + self.__falseNorth.GetValue()]
938
939 params.extend(ProjPanel.GetParameters(self))
940 return params
941
942 def Clear(self):
943 self.__fspLatitude.Clear()
944 self.__sspLatitude.Clear()
945 self.__originLat.Clear()
946 self.__meridian.Clear()
947 self.__falseEast.Clear()
948 self.__falseNorth.Clear()
949
950 ProjPanel.Clear(self)
951
952 class GeoPanel(ProjPanel):
953 """Projection Panel for a Geographic Projection."""
954
955 def __init__(self, parent, receiver):
956 ProjPanel.__init__(self, parent)
957
958 self.__choices = [(_("Degrees"), "0.017453"),
959 (_("Radians"), "1")]
960
961 self.__scale = wxChoice(self, -1)
962 for choice, value in self.__choices:
963 self.__scale.Append(choice, value)
964
965 self._DoLayout()
966
967 def GetProjName(self):
968 return _("Geographic")
969
970 def SetProjection(self, proj):
971 value = proj.GetParameter("to_meter")
972 for i in range(len(self.__choices)):
973 choice, data = self.__choices[i]
974 if value == data:
975 self.__scale.SetSelection(i)
976 ProjPanel.SetProjection(self, proj)
977
978 def GetParameters(self):
979 params = ["proj=latlong",
980 "to_meter=%s" % self.__scale.GetClientData(
981 self.__scale.GetSelection())]
982
983 params.extend(ProjPanel.GetParameters(self))
984 return params
985
986 def Clear(self):
987 ProjPanel.Clear(self)
988
989 def _DoLayout(self):
990 sizer = wxBoxSizer(wxHORIZONTAL)
991
992 sizer.Add(wxStaticText(self, -1, _("Source Data is in: ")),
993 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
994 sizer.Add(self.__scale, 1, wxEXPAND|wxALL, 4)
995
996 self.__scale.SetSelection(0)
997
998 ProjPanel._DoLayout(self, sizer)
999
1000
1001 ID_UTM_PROPOSE_ZONE_DIALOG_TAKE = 4001
1002 ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL = 4002
1003 class UTMProposeZoneDialog(wxDialog):
1004
1005 """Propose a sensible Zone considering the current map extent."""
1006
1007 def __init__(self, parent, (x, y, x2, y2)):
1008 wxDialog.__init__(self, parent, -1, _("Projection: Propose UTM Zone"),
1009 wxDefaultPosition, wxSize(200, 100))
1010 self.parent = parent
1011 x = x + 180
1012 x2 = x2 + 180
1013 center = (x2 - x) / 2 + x
1014 self.proposedZone = int(center / 6 + 1)
1015 self.dialogLayout()
1016
1017 def dialogLayout(self):
1018 topBox = wxBoxSizer(wxVERTICAL)
1019
1020 textBox = wxBoxSizer(wxVERTICAL)
1021 textBox.Add(wxStaticText(self, -1, _("The current map extent center "
1022 "lies in UTM Zone")),
1023 0, wxALIGN_CENTER|wxALL, 4)
1024 textBox.Add(wxStaticText(self, -1, str(self.proposedZone)),
1025 0, wxALIGN_CENTER|wxALL, 4)
1026
1027 topBox.Add(textBox, 1, wxEXPAND|wxALL, 4)
1028
1029 buttonBox = wxBoxSizer(wxHORIZONTAL)
1030 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE,
1031 _("Take")), 0, wxALL, 4)
1032 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL,
1033 _("Cancel")), 0, wxALL, 4)
1034 topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
1035 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE, self.OnTake)
1036 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL, self.OnCancel)
1037
1038 self.SetAutoLayout(True)
1039 self.SetSizer(topBox)
1040 topBox.Fit(self)
1041 topBox.SetSizeHints(self)
1042
1043 def OnTake(self, event):
1044 self.EndModal(wxID_OK)
1045
1046 def OnCancel(self, event):
1047 self.EndModal(wxID_CANCEL)
1048
1049 def GetProposedZone(self):
1050 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