/[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 1786 - (show annotations)
Wed Oct 8 10:39:11 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: 35387 byte(s)
* Thuban/Model/resource.py (read_proj_file): Return the warnings
too. Update the doc-string
(get_proj_files): Removed. It wasn't used anywhere
(get_system_proj_files, get_system_proj_file): Rename to
get_system_proj_file and return the ProjFile object and not a list
of ProjFile objects. Update the callers.
(get_user_proj_files, get_user_proj_file): Rename to
get_user_proj_file return the ProjFile object and not a list of
ProjFile objects. Update the callers.
(ProjFileReader.__init__): New instance variable for the warnings.
Rename the __pf ivar to projfile. Update the methods referring to
__pf
(ProjFileReader.end_projection): Catch any errors raised when
instantiating the projection and record that as an error. The
projection will not be in the final ProjFile object.
(ProjFileReader.GetWarnings): New method to return the warnings.

* Thuban/UI/projdialog.py (ProjFrame.show_warnings): New method to
show the warnings from the projfile reader
(ProjFrame._OnImport): Deal with any warnings returned by
read_proj_file
(ProjFrame.__FillAvailList): Deal with any warnings returned by
get_system_proj_file or get_user_proj_file.

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