/[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 1941 - (show annotations)
Tue Nov 11 18:27:48 2003 UTC (21 years, 3 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/projdialog.py
File MIME type: text/x-python
File size: 37133 byte(s)
(ProjFrame.build_dialog): Add a space
above the EPS widgets, introduce a check box for the deprecated
eps projections and a label for the epsg widgets
(ProjFrame._OnShowEPSG): Handle the deprecated EPSG projections
too

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