/[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 2022 - (show annotations)
Fri Dec 5 13:36:10 2003 UTC (21 years, 3 months ago) by frank
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 37171 byte(s)
Thuban/UI/projdialog.py (load_user_proj): If user.proj is missing
	write warning to stderr instead of rising a warning dialog

1 # Copyright (c) 2003 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"), style = wxOPEN)
307
308 if dlg.ShowModal() == wxID_OK:
309 path = dlg.GetPath()
310
311 ThubanBeginBusyCursor()
312 try:
313 try:
314 projFile, warnings = read_proj_file(path)
315 except IOError, (errno, errstr):
316 self.__ShowError(dlg.GetPath(), errstr)
317 else:
318 self.show_warnings(_("Warnings"), path, warnings)
319 for proj in projFile.GetProjections():
320 self.__usrProjFile.Add(proj)
321 self.write_proj_file(self.__usrProjFile)
322 finally:
323 ThubanEndBusyCursor()
324 dlg.Destroy()
325
326 def _OnExport(self, event):
327 """Handler for the 'Export' button.
328
329 Ask the user for a filename and write the selected projections
330 to that file.
331 """
332 sel = self.projection_list.selected_projections()
333 assert len(sel) != 0, "button should be disabled"
334
335 dlg = wxFileDialog(self, _("Export"), style=wxSAVE|wxOVERWRITE_PROMPT)
336
337 if dlg.ShowModal() == wxID_OK:
338 proj_file = ProjFile(dlg.GetPath())
339 for proj, pf in sel:
340 if proj is not None:
341 proj_file.Add(proj)
342 self.write_proj_file(proj_file)
343
344 dlg.Destroy()
345
346 def _OnRemove(self, event):
347 """Handler for the 'Remove' button
348
349 Remove any selected projection that came from the user's
350 ProjFile. If the user ProjFile was modified write it back to
351 disk.
352 """
353 sel = self.projection_list.selected_projections()
354 assert len(sel) != 0, "button should be disabled!"
355
356 modified = False
357 for proj, pf in sel:
358 if proj is not None and pf is self.__usrProjFile:
359 pf.Remove(proj)
360 modified = True
361
362 if modified:
363 self.write_proj_file(self.__usrProjFile)
364
365 def _OnShowEPSG(self, event):
366 """Handler for the EVT_CHECKBOX events from the EPSG check button
367
368 If the button is checked add the EPSG_PROJ_FILE to the list of
369 projfiles shown by the projection list. Otherwise remove it
370 """
371 proj_files = [self.load_user_proj(),
372 self.load_system_proj(DEFAULT_PROJ_FILE)]
373 if self.check_epsg.IsChecked():
374 proj_files.append(self.load_system_proj(EPSG_PROJ_FILE))
375 if self.check_epsg_depr.IsChecked():
376 proj_files.append(self.load_system_proj(EPSG_DEPRECATED_PROJ_FILE))
377 self.projection_list.SetProjFiles(proj_files)
378
379 def _OnProjName(self, event):
380 self.__VerifyButtons()
381
382 def __ShowError(self, filename, errstr):
383 wxMessageDialog(self,
384 _("The following error occured:\n") +
385 filename + "\n" + errstr,
386 _("Error"), wxOK | wxICON_ERROR).ShowModal()
387
388 def __VerifyButtons(self):
389 """Update button sensitivity"""
390
391 num_sel = self.projection_list.GetSelectedItemCount()
392
393 self.button_import.Enable(True)
394 self.button_export.Enable(True)
395 self.button_save.Enable(True)
396 self.button_remove.Enable(True)
397
398 self.edit_box.Enable(True)
399
400 for ctrl in [self.button_import,
401 self.button_export,
402 self.button_remove,
403 self.button_save,
404 self.button_add,
405 self.projchoice,
406 self.projname,
407 self.edit_box]:
408 ctrl.Enable(True)
409
410 if self.curProjPanel is not None:
411 self.curProjPanel.Enable(True)
412
413 if num_sel == 0:
414 self.button_import.Enable(True)
415 self.button_export.Enable(False)
416 self.button_remove.Enable(False)
417 self.button_save.Enable(False)
418
419 elif num_sel == 1:
420
421 selection = self.projection_list.selected_projections()
422 proj, projFile = selection[0]
423
424 self.button_save.Enable(len(self.projname.GetValue()) > 0)
425 self.button_add.Enable(len(self.projname.GetValue()) > 0)
426
427 if proj is None:
428 # <None> is selected
429 for ctrl in [self.button_export,
430 self.button_remove,
431 self.button_save,
432 self.button_add,
433 self.projchoice,
434 self.projname]:
435 ctrl.Enable(False)
436
437 if self.curProjPanel is not None:
438 self.curProjPanel.Enable(False)
439
440 elif proj is self.originalProjection:
441 self.button_remove.Enable(False)
442
443 if projFile is None:
444 self.button_save.Enable(False)
445
446 else:
447 self.edit_box.Enable(False)
448
449 def proj_selection_changed(self, projs):
450 """Subscribed to the projection_list's PROJ_SELECTION_CHANGED message
451
452 Update the dialog to reflect the new selection.
453 """
454 if len(projs) == 0:
455 self.projfilepath.SetLabel(_("No Projections selected"))
456 elif len(projs) == 1:
457 proj, projfile = projs[0]
458 if proj is None:
459 # user selected <None>
460 self.projname.Clear()
461 self.projfilepath.SetLabel("")
462 else:
463 if projfile is not None:
464 filename = os.path.basename(projfile.GetFilename())
465 self.projfilepath.SetLabel(_("Source of Projection: %s")
466 % filename)
467 else:
468 # only None if the currently used projection is selected
469 self.projfilepath.SetLabel("")
470
471 self.projname.SetValue(proj.Label())
472
473 myProjType = proj.GetParameter("proj")
474 i = 0
475 for projType, name, cls in self.projection_panel_defs:
476 if myProjType == projType:
477 self.projchoice.Enable(True)
478 self.projchoice.SetSelection(i + 1)
479 self.__DoOnProjChoice()
480
481 #
482 # self.curProjPanel should not be null
483 # after a call to __DoOnProjChoice
484 #
485 assert self.curProjPanel is not None
486
487 self.curProjPanel.SetProjection(proj)
488 break
489 i += 1
490 else:
491 self.projchoice.Select(0)
492 self.projchoice.Disable()
493 self._show_proj_panel(UnknownProjPanel)
494 assert self.curProjPanel is not None
495 self.curProjPanel.SetProjection(proj)
496 else:
497 self.projfilepath.SetLabel(_("Multiple Projections selected"))
498
499 self.__VerifyButtons()
500
501 def _OnProjChoice(self, event):
502 self.__DoOnProjChoice()
503
504 def __DoOnProjChoice(self):
505 """Create and layout a projection panel based on the selected
506 projection type.
507
508 This is necessary to have in seperate method since calls to
509 wxChoice.SetSelection() do not trigger an event.
510
511 At the end of this method self.curProjPanel will not be None
512 if there was a item selected.
513 """
514 choice = self.projchoice
515
516 sel = choice.GetSelection()
517 if sel != -1:
518 proj_type = choice.GetClientData(sel)
519 for t, name, cls in self.projection_panel_defs:
520 if t == proj_type:
521 self._show_proj_panel(cls)
522 break
523 # FIXME: what to do if sel == -1?
524
525 def _show_proj_panel(self, panel_class):
526 """Show the panel as the projection panel"""
527 if panel_class is UnknownProjPanel:
528 self.edit_box.Disable()
529 self.nbsizer.Activate(self.unknown_projection_panel)
530 self.curProjPanel = self.unknown_projection_panel
531 else:
532 self.edit_box.Enable(True)
533 self.unknown_projection_panel.Hide()
534 for panel in self.projection_panels:
535 if panel.__class__ is panel_class:
536 self.nbsizer.Activate(panel)
537 self.curProjPanel = panel
538
539 def __SetProjection(self):
540 """Set the receiver's projection."""
541
542 #
543 # save the original projection only once in case
544 # we try to apply several different projections
545 #
546 self.receiver.SetProjection(self.__GetProjection())
547
548 def __GetProjection(self):
549 """Return a suitable Projection object based on the current
550 state of the dialog box selections.
551
552 Could be None.
553 """
554
555 assert self.projection_list.GetSelectedItemCount() < 2, \
556 "button should be disabled"
557
558 sel = self.projection_list.selected_projections()
559 if len(sel) == 1:
560 if sel[0][0] is None:
561 # <None> is selected
562 return None
563
564 # self.curProjPanel should always contain the most relevant data
565 # for a projection
566 if self.curProjPanel is not None:
567 return Projection(self.curProjPanel.GetParameters(),
568 self.projname.GetValue())
569
570 return None
571
572 def load_user_proj(self):
573 """Return the user's ProjFile
574
575 If the file has not yet been loaded by the dialog, load it first
576 with get_user_proj_file and cache it in self.__usrProjFile.
577
578 Show a busy cursor while loading the file.
579
580 If the file is not available, leave a note to the console.
581 """
582 if self.__usrProjFile is None:
583 ThubanBeginBusyCursor()
584 try:
585 projfile, warnings = get_user_proj_file()
586 if warnings:
587 sys.stderr.write("".join(warnings))
588 self.__usrProjFile = projfile
589 finally:
590 ThubanEndBusyCursor()
591 return self.__usrProjFile
592
593 def load_system_proj(self, name):
594 """Load the system ProjFile with the given name.
595
596 If the file has not been loaded yet, load it first with
597 get_system_proj_file and put it into the cache. The name is
598 simply forwarded to get_system_proj_file.
599
600 Show a busy cursor while loading the file.
601 """
602 if name not in self._sys_proj_files:
603 ThubanBeginBusyCursor()
604 try:
605 projfile, warnings = get_system_proj_file(name)
606 self.show_warnings(_("Warnings"), projfile.GetFilename(),
607 warnings)
608 self._sys_proj_files[name] = projfile
609 finally:
610 ThubanEndBusyCursor()
611 return self._sys_proj_files[name]
612
613 def write_proj_file(self, proj_file):
614 """Write the ProjFile object proj_file back to its file
615
616 Show a busy cursor while writing and if an error occurs show a
617 dialog with the error message.
618 """
619 try:
620 ThubanBeginBusyCursor()
621 try:
622 write_proj_file(proj_file)
623 finally:
624 ThubanEndBusyCursor()
625 except IOError, (errno, errstr):
626 self.__ShowError(proj_file.GetFilename(), errstr)
627
628
629
630 class ProjPanel(wxPanel):
631 """Base class for all projection panels."""
632
633 def __init__(self, parent):
634 wxPanel.__init__(self, parent, -1)
635
636 self.__ellps = wxChoice(self, -1)
637 self.ellpsData = [("", _("<Unknown>")),
638 ("airy" , _("Airy")),
639 ("bessel", _("Bessel 1841")),
640 ("clrk66", _("Clarke 1866")),
641 ("clrk80", _("Clarke 1880")),
642 ("GRS80" , _("GRS 1980 (IUGG, 1980)")),
643 ("intl" , _("International 1909 (Hayford)")),
644 ("WGS84" , _("WGS 84"))]
645
646 for tag, name in self.ellpsData:
647 self.__ellps.Append(name, tag)
648
649 self.__ellps.SetSelection(0)
650
651 def _DoLayout(self, childPanel = None):
652
653 panelSizer = wxBoxSizer(wxVERTICAL)
654
655 sizer = wxBoxSizer(wxHORIZONTAL)
656 sizer.Add(wxStaticText(self, -1, _("Ellipsoid:")), 0,
657 wxALL|wxALIGN_CENTER_VERTICAL, 4)
658 sizer.Add(self.__ellps, 1, wxALL|wxALIGN_CENTER_VERTICAL, 4)
659 panelSizer.Add(sizer, 0, wxALL|wxEXPAND, 4)
660
661 if childPanel is not None:
662 panelSizer.Add(childPanel, 0, wxEXPAND, 0)
663
664 self.SetAutoLayout(1)
665 self.SetSizer(panelSizer)
666 panelSizer.Fit(self)
667 panelSizer.SetSizeHints(self)
668 self.Layout()
669
670 def SetProjection(self, proj):
671 if proj is not None:
672 param = proj.GetParameter("ellps")
673 i = 0
674 for tag, name in self.ellpsData:
675 if param == tag:
676 self.__ellps.SetSelection(i)
677 return # returning early!
678 i += 1
679
680 #
681 # if proj is none, or the parameter couldn't be found...
682 #
683 self.__ellps.SetSelection(0)
684
685 def GetParameters(self):
686 ellps = self.__ellps.GetSelection()
687 if ellps > 0:
688 return ["ellps=" + self.__ellps.GetClientData(ellps)]
689 return []
690
691
692 ID_TMPANEL_LAT = 4001
693 ID_TMPANEL_LONG = 4002
694 ID_TMPANEL_FASLE_EAST = 4003
695 ID_TMPANEL_FALSE_NORTH = 4004
696 ID_TMPANEL_SCALE = 4005
697
698 class UnknownProjPanel(ProjPanel):
699
700 """Panel for unknown projection types"""
701
702 def __init__(self, parent, receiver):
703 ProjPanel.__init__(self, parent)
704
705 self.__text = _("Thuban does not know the parameters\n"
706 "for the current projection and cannot\n"
707 "display a configuration panel.\n\n"
708 "The unidentified set of parameters is:\n\n")
709
710 self.__textbox = wxTextCtrl(self, -1, self.__text, size=(100,200),
711 style=wxTE_READONLY|wxTE_MULTILINE|wxTE_LINEWRAP)
712 self._DoLayout()
713
714 def _DoLayout(self):
715 sizer = wxBoxSizer(wxVERTICAL)
716
717 sizer.Add(self.__textbox, 0, wxALL|wxEXPAND, 4)
718
719 ProjPanel._DoLayout(self, sizer)
720
721 def GetProjName(self):
722 return "Unknown"
723
724 def SetProjection(self, proj):
725 """Append the available parameters to the info text."""
726 text = self.__text
727 for param in proj.GetAllParameters():
728 text = text + '%s\n' % param
729 self.__textbox.SetValue(text)
730
731 def GetParameters(self):
732 return None
733
734 class TMPanel(ProjPanel):
735 """Projection panel for Transverse Mercator."""
736
737 def __init__(self, parent, receiver):
738 ProjPanel.__init__(self, parent)
739
740 self.__latitude = wxTextCtrl(self, ID_TMPANEL_LAT)
741 self.__longitude = wxTextCtrl(self, ID_TMPANEL_LONG)
742 self.__falseEast = wxTextCtrl(self, ID_TMPANEL_FASLE_EAST)
743 self.__falseNorth = wxTextCtrl(self, ID_TMPANEL_FALSE_NORTH)
744 self.__scale = wxTextCtrl(self, ID_TMPANEL_SCALE)
745
746 self._DoLayout()
747
748 def _DoLayout(self):
749
750 sizer = wxFlexGridSizer(4, 2, 0, 0)
751 sizer.Add(wxStaticText(self, -1, _("Latitude:")), 0, wxALL, 4)
752 sizer.Add(self.__latitude, 0, wxALL, 4)
753 sizer.Add(wxStaticText(self, -1, _("Longitude:")), 0, wxALL, 4)
754 sizer.Add(self.__longitude, 0, wxALL, 4)
755 sizer.Add(wxStaticText(self, -1, _("False Easting:")), 0, wxALL, 4)
756 sizer.Add(self.__falseEast, 0, wxALL, 4)
757 sizer.Add(wxStaticText(self, -1, _("False Northing:")), 0, wxALL, 4)
758 sizer.Add(self.__falseNorth, 0, wxALL, 4)
759 sizer.Add(wxStaticText(self, -1, _("Scale Factor:")), 0, wxALL, 4)
760 sizer.Add(self.__scale, 0, wxALL, 4)
761
762 ProjPanel._DoLayout(self, sizer)
763
764 def GetProjName(self):
765 return _("Transverse Mercator")
766
767 def SetProjection(self, proj):
768 ProjPanel.SetProjection(self, proj)
769
770 self.__latitude.SetValue(proj.GetParameter("lat_0"))
771 self.__longitude.SetValue(proj.GetParameter("lon_0"))
772 self.__falseEast.SetValue(proj.GetParameter("x_0"))
773 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
774 self.__scale.SetValue(proj.GetParameter("k"))
775
776 ProjPanel.SetProjection(self, proj)
777
778 def GetParameters(self):
779 params = ["proj=tmerc",
780 "lat_0=" + self.__latitude.GetValue(),
781 "lon_0=" + self.__longitude.GetValue(),
782 "x_0=" + self.__falseEast.GetValue(),
783 "y_0=" + self.__falseNorth.GetValue(),
784 "k=" + self.__scale.GetValue()]
785 params.extend(ProjPanel.GetParameters(self))
786 return params
787
788 def Clear(self):
789 self.__latitude.Clear()
790 self.__longitude.Clear()
791 self.__falseEast.Clear()
792 self.__falseNorth.Clear()
793 self.__scale.Clear()
794
795 ProjPanel.Clear(self)
796
797 ID_UTMPANEL_ZONE = 4001
798 ID_UTMPANEL_SOUTH = 4002
799 ID_UTMPANEL_PROP = 4003
800
801 class UTMPanel(ProjPanel):
802 """Projection Panel for Universal Transverse Mercator."""
803
804 def __init__(self, parent, receiver):
805 ProjPanel.__init__(self, parent)
806
807 self.receiver = receiver
808
809 self.__zone = wxSpinCtrl(self, ID_UTMPANEL_ZONE, "1", min=1, max=60)
810 self.__propButton = wxButton(self, ID_UTMPANEL_PROP, _("Propose"))
811 self.__south = wxCheckBox(self, ID_UTMPANEL_SOUTH,
812 _("Southern Hemisphere"))
813
814 self._DoLayout()
815
816 EVT_BUTTON(self, ID_UTMPANEL_PROP, self._OnPropose)
817
818 def _DoLayout(self):
819
820 sizer = wxBoxSizer(wxVERTICAL)
821 psizer = wxBoxSizer(wxHORIZONTAL)
822 psizer.Add(wxStaticText(self, -1, _("Zone:")), 0, wxALL, 4)
823 psizer.Add(self.__zone, 0, wxALL, 4)
824 psizer.Add(self.__propButton, 0, wxALL, 4)
825 sizer.Add(psizer, 0, wxALL, 4)
826 sizer.Add(self.__south, 0, wxALL, 4)
827
828 ProjPanel._DoLayout(self, sizer)
829
830 def GetProjName(self):
831 return _("Universal Transverse Mercator")
832
833 def SetProjection(self, proj):
834 self.__zone.SetValue(int(proj.GetParameter("zone")))
835 self.__south.SetValue(proj.GetParameter("south") != "")
836 ProjPanel.SetProjection(self, proj)
837
838 def GetParameters(self):
839 params = ["proj=utm", "zone=" + str(self.__zone.GetValue())]
840 if self.__south.IsChecked():
841 params.append("south")
842
843 params.extend(ProjPanel.GetParameters(self))
844 return params
845
846 def Clear(self):
847 self.__zone.SetValue(1)
848 self.__south.SetValue(False)
849 ProjPanel.Clear(self)
850
851 def _OnPropose(self, event):
852 """Call the propose dialog.
853 If the receiver (e.g. the current map) has no bounding box,
854 inform the user accordingly.
855 """
856 bb = self.receiver.BoundingBox()
857 if bb is None:
858 dlg = wxMessageDialog(self,
859 _("Can not propose: No bounding box found."),
860 _("Projection: Propose UTM Zone"),
861 wxOK | wxICON_INFORMATION)
862 dlg.CenterOnParent()
863 result = dlg.ShowModal()
864 dlg.Destroy()
865 return
866
867 dlg = UTMProposeZoneDialog(self, self.receiver.BoundingBox())
868 if dlg.ShowModal() == wxID_OK:
869 self.__zone.SetValue(dlg.GetProposedZone())
870
871 class LCCPanel(ProjPanel):
872 """Projection Panel for Lambert Conic Conformal."""
873
874 def __init__(self, parent, receiver):
875 ProjPanel.__init__(self, parent)
876
877 self.__fspLatitude = wxTextCtrl(self, -1)
878 self.__sspLatitude = wxTextCtrl(self, -1)
879 self.__meridian = wxTextCtrl(self, -1)
880 self.__originLat = wxTextCtrl(self, -1)
881 self.__falseEast = wxTextCtrl(self, -1)
882 self.__falseNorth = wxTextCtrl(self, -1)
883
884 self._DoLayout()
885
886 def _DoLayout(self):
887
888 sizer = wxFlexGridSizer(6, 2, 0, 0)
889 sizer.Add(wxStaticText(self, -1,
890 _("Latitude of first standard parallel:")))
891 sizer.Add(self.__fspLatitude, 0, wxALL, 4)
892 sizer.Add(wxStaticText(self, -1,
893 _("Latitude of second standard parallel:")))
894 sizer.Add(self.__sspLatitude, 0, wxALL, 4)
895 sizer.Add(wxStaticText(self, -1, _("Central Meridian:")))
896 sizer.Add(self.__meridian, 0, wxALL, 4)
897 sizer.Add(wxStaticText(self, -1, _("Latitude of origin:")))
898 sizer.Add(self.__originLat, 0, wxALL, 4)
899 sizer.Add(wxStaticText(self, -1, _("False Easting:")))
900 sizer.Add(self.__falseEast, 0, wxALL, 4)
901 sizer.Add(wxStaticText(self, -1, _("False Northing:")))
902 sizer.Add(self.__falseNorth, 0, wxALL, 4)
903
904 ProjPanel._DoLayout(self, sizer)
905
906 def GetProjName(self):
907 return _("Lambert Conic Conformal")
908
909 def SetProjection(self, proj):
910 self.__fspLatitude.SetValue(proj.GetParameter("lat_1"))
911 self.__sspLatitude.SetValue(proj.GetParameter("lat_2"))
912 self.__originLat.SetValue(proj.GetParameter("lat_0"))
913 self.__meridian.SetValue(proj.GetParameter("lon_0"))
914 self.__falseEast.SetValue(proj.GetParameter("x_0"))
915 self.__falseNorth.SetValue(proj.GetParameter("y_0"))
916
917 ProjPanel.SetProjection(self, proj)
918
919 def GetParameters(self):
920 params = ["proj=lcc",
921 "lat_1=" + self.__fspLatitude.GetValue(),
922 "lat_2=" + self.__sspLatitude.GetValue(),
923 "lat_0=" + self.__originLat.GetValue(),
924 "lon_0=" + self.__meridian.GetValue(),
925 "x_0=" + self.__falseEast.GetValue(),
926 "y_0=" + self.__falseNorth.GetValue()]
927
928 params.extend(ProjPanel.GetParameters(self))
929 return params
930
931 def Clear(self):
932 self.__fspLatitude.Clear()
933 self.__sspLatitude.Clear()
934 self.__originLat.Clear()
935 self.__meridian.Clear()
936 self.__falseEast.Clear()
937 self.__falseNorth.Clear()
938
939 ProjPanel.Clear(self)
940
941 class GeoPanel(ProjPanel):
942 """Projection Panel for a Geographic Projection."""
943
944 def __init__(self, parent, receiver):
945 ProjPanel.__init__(self, parent)
946
947 self.__choices = [(_("Degrees"), "0.017453"),
948 (_("Radians"), "1")]
949
950 self.__scale = wxChoice(self, -1)
951 for choice, value in self.__choices:
952 self.__scale.Append(choice, value)
953
954 self._DoLayout()
955
956 def GetProjName(self):
957 return _("Geographic")
958
959 def SetProjection(self, proj):
960 value = proj.GetParameter("to_meter")
961 for i in range(len(self.__choices)):
962 choice, data = self.__choices[i]
963 if value == data:
964 self.__scale.SetSelection(i)
965 ProjPanel.SetProjection(self, proj)
966
967 def GetParameters(self):
968 params = ["proj=latlong",
969 "to_meter=%s" % self.__scale.GetClientData(
970 self.__scale.GetSelection())]
971
972 params.extend(ProjPanel.GetParameters(self))
973 return params
974
975 def Clear(self):
976 ProjPanel.Clear(self)
977
978 def _DoLayout(self):
979 sizer = wxBoxSizer(wxHORIZONTAL)
980
981 sizer.Add(wxStaticText(self, -1, _("Source Data is in: ")),
982 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
983 sizer.Add(self.__scale, 1, wxEXPAND|wxALL, 4)
984
985 self.__scale.SetSelection(0)
986
987 ProjPanel._DoLayout(self, sizer)
988
989
990 ID_UTM_PROPOSE_ZONE_DIALOG_TAKE = 4001
991 ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL = 4002
992 class UTMProposeZoneDialog(wxDialog):
993
994 """Propose a sensible Zone considering the current map extent."""
995
996 def __init__(self, parent, (x, y, x2, y2)):
997 wxDialog.__init__(self, parent, -1, _("Projection: Propose UTM Zone"),
998 wxDefaultPosition, wxSize(200, 100))
999 self.parent = parent
1000 x = x + 180
1001 x2 = x2 + 180
1002 center = (x2 - x) / 2 + x
1003 self.proposedZone = int(center / 6 + 1)
1004 self.dialogLayout()
1005
1006 def dialogLayout(self):
1007 topBox = wxBoxSizer(wxVERTICAL)
1008
1009 textBox = wxBoxSizer(wxVERTICAL)
1010 textBox.Add(wxStaticText(self, -1, _("The current map extent center "
1011 "lies in UTM Zone")),
1012 0, wxALIGN_CENTER|wxALL, 4)
1013 textBox.Add(wxStaticText(self, -1, str(self.proposedZone)),
1014 0, wxALIGN_CENTER|wxALL, 4)
1015
1016 topBox.Add(textBox, 1, wxEXPAND|wxALL, 4)
1017
1018 buttonBox = wxBoxSizer(wxHORIZONTAL)
1019 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE,
1020 _("Take")), 0, wxALL, 4)
1021 buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL,
1022 _("Cancel")), 0, wxALL, 4)
1023 topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
1024 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE, self.OnTake)
1025 EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL, self.OnCancel)
1026
1027 self.SetAutoLayout(True)
1028 self.SetSizer(topBox)
1029 topBox.Fit(self)
1030 topBox.SetSizeHints(self)
1031
1032 def OnTake(self, event):
1033 self.EndModal(wxID_OK)
1034
1035 def OnCancel(self, event):
1036 self.EndModal(wxID_CANCEL)
1037
1038 def GetProposedZone(self):
1039 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