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