/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/mainwindow.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/mainwindow.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 879 - (hide annotations)
Fri May 9 16:33:10 2003 UTC (21 years, 10 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 33413 byte(s)
Add support for the Join Dialog. Added a Table menu and associated method calls.
(MainWindow.choose_color): Removed. No longer needed.

1 bh 535 # Copyright (C) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Jan-Oliver Wagner <[email protected]>
4     # Bernhard Herzog <[email protected]>
5     #
6     # This program is free software under the GPL (>=v2)
7     # Read the file COPYING coming with Thuban for details.
8    
9     """
10     The main window
11     """
12    
13     __version__ = "$Revision$"
14    
15 jonathan 517 __ThubanVersion__ = "0.2" #"$THUBAN_0_2$"
16     #__BuildDate__ = "$Date$"
17    
18 bh 188 import os
19 bh 6
20     from wxPython.wx import *
21    
22     import Thuban
23 jan 374 from Thuban import _
24 bh 188 from Thuban.Model.session import create_empty_session
25 bh 6 from Thuban.Model.layer import Layer
26     from Thuban.Model.color import Color
27     from Thuban.Model.proj import Projection
28    
29     import view
30     import tree
31     import proj4dialog
32     import tableview, identifyview
33 jonathan 633 from Thuban.UI.classifier import Classifier
34 jonathan 550 import legend
35 bh 188 from menu import Menu
36 bh 6
37 bh 222 from context import Context
38 bh 357 from command import registry, Command, ToolCommand
39 bh 704 from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION
40 bh 6
41 bh 704 from Thuban.UI.dock import DockFrame
42 jonathan 879 from Thuban.UI.join import JoinDialog
43 bh 6
44 jonathan 653 import resource
45 jonathan 563
46 jonathan 713 import projdialog
47 jonathan 653
48 bh 6
49 jonathan 713
50 jonathan 573 class MainWindow(DockFrame):
51 bh 6
52 bh 535 # Some messages that can be subscribed/unsubscribed directly through
53     # the MapCanvas come in fact from other objects. This is a map to
54     # map those messages to the names of the instance variables they
55     # actually come from. This delegation is implemented in the
56     # Subscribe and unsubscribed methods
57     delegated_messages = {LAYER_SELECTED: "canvas",
58     SHAPES_SELECTED: "canvas"}
59    
60     # Methods delegated to some instance variables. The delegation is
61     # implemented in the __getattr__ method.
62     delegated_methods = {"SelectLayer": "canvas",
63     "SelectShapes": "canvas",
64 jonathan 879 "SelectedShapes": "canvas",
65 bh 535 }
66    
67 bh 235 def __init__(self, parent, ID, title, application, interactor,
68 bh 238 initial_message = None, size = wxSize(-1, -1)):
69 jonathan 573 DockFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
70     #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
71 bh 6
72 bh 227 self.application = application
73 bh 37
74 bh 6 self.CreateStatusBar()
75 bh 235 if initial_message:
76     self.SetStatusText(initial_message)
77 bh 6
78     self.identify_view = None
79    
80     self.init_ids()
81    
82 bh 191 # creat the menubar from the main_menu description
83 bh 188 self.SetMenuBar(self.build_menu_bar(main_menu))
84 bh 6
85 bh 191 # Similarly, create the toolbar from main_toolbar
86     toolbar = self.build_toolbar(main_toolbar)
87 bh 13 # call Realize to make sure that the tools appear.
88     toolbar.Realize()
89 bh 6
90 jonathan 563
91 bh 6 # Create the map canvas
92 bh 535 canvas = view.MapCanvas(self, -1)
93 bh 123 canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
94 bh 535 canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
95 bh 6 self.canvas = canvas
96    
97 jonathan 573 self.SetMainWindow(self.canvas)
98    
99 jonathan 563 self.SetAutoLayout(True)
100    
101 bh 31 self.init_dialogs()
102    
103 jonathan 580 EVT_CLOSE(self, self._OnClose)
104 bh 6
105 bh 535 def Subscribe(self, channel, *args):
106     """Subscribe a function to a message channel.
107    
108     If channel is one of the delegated messages call the appropriate
109     object's Subscribe method. Otherwise do nothing.
110     """
111     if channel in self.delegated_messages:
112     object = getattr(self, self.delegated_messages[channel])
113     object.Subscribe(channel, *args)
114     else:
115     print "Trying to subscribe to unsupported channel %s" % channel
116    
117     def Unsubscribe(self, channel, *args):
118     """Unsubscribe a function from a message channel.
119    
120     If channel is one of the delegated messages call the appropriate
121     object's Unsubscribe method. Otherwise do nothing.
122     """
123     if channel in self.delegated_messages:
124     object = getattr(self, self.delegated_messages[channel])
125     object.Unsubscribe(channel, *args)
126    
127     def __getattr__(self, attr):
128     """If attr is one of the delegated methods return that method
129    
130     Otherwise raise AttributeError.
131     """
132     if attr in self.delegated_methods:
133     return getattr(getattr(self, self.delegated_methods[attr]), attr)
134     raise AttributeError(attr)
135    
136 bh 6 def init_ids(self):
137     """Initialize the ids"""
138     self.current_id = 6000
139     self.id_to_name = {}
140     self.name_to_id = {}
141 bh 193 self.events_bound = {}
142 bh 6
143     def get_id(self, name):
144     """Return the wxWindows id for the command named name.
145    
146     Create a new one if there isn't one yet"""
147     ID = self.name_to_id.get(name)
148     if ID is None:
149     ID = self.current_id
150     self.current_id = self.current_id + 1
151     self.name_to_id[name] = ID
152     self.id_to_name[ID] = name
153     return ID
154 bh 188
155 bh 193 def bind_command_events(self, command, ID):
156     """Bind the necessary events for the given command and ID"""
157     if not self.events_bound.has_key(ID):
158     # the events haven't been bound yet
159     EVT_MENU(self, ID, self.invoke_command)
160     if command.IsDynamic():
161     EVT_UPDATE_UI(self, ID, self.update_command_ui)
162    
163 bh 188 def build_menu_bar(self, menudesc):
164     """Build and return the menu bar from the menu description"""
165     menu_bar = wxMenuBar()
166    
167     for item in menudesc.items:
168     # here the items must all be Menu instances themselves
169     menu_bar.Append(self.build_menu(item), item.title)
170    
171     return menu_bar
172    
173     def build_menu(self, menudesc):
174 bh 314 """Return a wxMenu built from the menu description menudesc"""
175 bh 188 wxmenu = wxMenu()
176     last = None
177     for item in menudesc.items:
178     if item is None:
179     # a separator. Only add one if the last item was not a
180     # separator
181     if last is not None:
182     wxmenu.AppendSeparator()
183     elif isinstance(item, Menu):
184     # a submenu
185     wxmenu.AppendMenu(wxNewId(), item.title, self.build_menu(item))
186     else:
187     # must the name the name of a command
188     self.add_menu_command(wxmenu, item)
189     last = item
190     return wxmenu
191    
192 bh 191 def build_toolbar(self, toolbardesc):
193     """Build and return the main toolbar window from a toolbar description
194    
195     The parameter should be an instance of the Menu class but it
196     should not contain submenus.
197     """
198     toolbar = self.CreateToolBar(wxTB_3DBUTTONS)
199    
200     # set the size of the tools' bitmaps. Not needed on wxGTK, but
201     # on Windows, although it doesn't work very well there. It seems
202     # that only 16x16 icons are really supported on windows.
203     # We probably shouldn't hardwire the bitmap size here.
204     toolbar.SetToolBitmapSize(wxSize(24, 24))
205    
206     for item in toolbardesc.items:
207     if item is None:
208     toolbar.AddSeparator()
209     else:
210     # assume it's a string.
211     self.add_toolbar_command(toolbar, item)
212    
213     return toolbar
214    
215 bh 6 def add_menu_command(self, menu, name):
216     """Add the command with name name to the menu menu.
217    
218     If name is None, add a separator.
219     """
220     if name is None:
221     menu.AppendSeparator()
222     else:
223     command = registry.Command(name)
224     if command is not None:
225     ID = self.get_id(name)
226     menu.Append(ID, command.Title(), command.HelpText(),
227     command.IsCheckCommand())
228 bh 193 self.bind_command_events(command, ID)
229 bh 6 else:
230 jan 374 print _("Unknown command %s") % name
231 bh 6
232     def add_toolbar_command(self, toolbar, name):
233     """Add the command with name name to the toolbar toolbar.
234    
235     If name is None, add a separator.
236     """
237     # Assume that all toolbar commands are also menu commmands so
238     # that we don't have to add the event handlers here
239     if name is None:
240     toolbar.AddSeparator()
241     else:
242     command = registry.Command(name)
243     if command is not None:
244     ID = self.get_id(name)
245 jonathan 653 bitmap = resource.GetBitmapResource(command.Icon(),
246     wxBITMAP_TYPE_XPM)
247 bh 6 toolbar.AddTool(ID, bitmap,
248     shortHelpString = command.HelpText(),
249     isToggle = command.IsCheckCommand())
250 bh 193 self.bind_command_events(command, ID)
251 bh 6 else:
252 jan 374 print _("Unknown command %s") % name
253 bh 6
254 bh 281 def Context(self):
255     """Return the context object for a command invoked from this window
256     """
257     return Context(self.application, self.application.Session(), self)
258    
259 bh 6 def invoke_command(self, event):
260     name = self.id_to_name.get(event.GetId())
261     if name is not None:
262     command = registry.Command(name)
263 bh 281 command.Execute(self.Context())
264 bh 6 else:
265 jan 374 print _("Unknown command ID %d") % event.GetId()
266 bh 6
267     def update_command_ui(self, event):
268     #print "update_command_ui", self.id_to_name[event.GetId()]
269 bh 281 context = self.Context()
270 bh 6 command = registry.Command(self.id_to_name[event.GetId()])
271     if command is not None:
272 bh 357 sensitive = command.Sensitive(context)
273     event.Enable(sensitive)
274     if command.IsTool() and not sensitive and command.Checked(context):
275     # When a checked tool command is disabled deselect all
276     # tools. Otherwise the tool would remain active but it
277     # might lead to errors if the tools stays active. This
278     # problem occurred in GREAT-ER and this fixes it, but
279     # it's not clear to me whether this is really the best
280     # way to do it (BH, 20021206).
281     self.canvas.SelectTool(None)
282 bh 222 event.SetText(command.DynText(context))
283 bh 13 if command.IsCheckCommand():
284 bh 357 event.Check(command.Checked(context))
285 bh 6
286 bh 20 def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
287 bh 181 """Run a modal message box with the given text, title and flags
288 bh 20 and return the result"""
289     dlg = wxMessageDialog(self, text, title, flags)
290 bh 316 dlg.CenterOnParent()
291 bh 20 result = dlg.ShowModal()
292     dlg.Destroy()
293     return result
294    
295 bh 31 def init_dialogs(self):
296     """Initialize the dialog handling"""
297     # The mainwindow maintains a dict mapping names to open
298     # non-modal dialogs. The dialogs are put into this dict when
299     # they're created and removed when they're closed
300     self.dialogs = {}
301    
302     def add_dialog(self, name, dialog):
303     if self.dialogs.has_key(name):
304 jan 374 raise RuntimeError(_("The Dialog named %s is already open") % name)
305 bh 31 self.dialogs[name] = dialog
306    
307     def dialog_open(self, name):
308     return self.dialogs.has_key(name)
309    
310     def remove_dialog(self, name):
311     del self.dialogs[name]
312    
313     def get_open_dialog(self, name):
314     return self.dialogs.get(name)
315    
316 bh 123 def view_position_changed(self):
317     pos = self.canvas.CurrentPosition()
318     if pos is not None:
319     text = "(%10.10g, %10.10g)" % pos
320     else:
321     text = ""
322 bh 321 self.set_position_text(text)
323    
324     def set_position_text(self, text):
325     """Set the statusbar text showing the current position.
326    
327     By default the text is shown in field 0 of the status bar.
328     Override this method in derived classes to put it into a
329     different field of the statusbar.
330     """
331 bh 123 self.SetStatusText(text)
332    
333 bh 58 def save_modified_session(self, can_veto = 1):
334     """If the current session has been modified, ask the user
335     whether to save it and do so if requested. Return the outcome of
336     the dialog (either wxID_OK, wxID_CANCEL or wxID_NO). If the
337     dialog wasn't run return wxID_NO.
338    
339     If the can_veto parameter is true (default) the dialog includes
340     a cancel button, otherwise not.
341     """
342 bh 227 if self.application.session.WasModified():
343 bh 58 flags = wxYES_NO | wxICON_QUESTION
344     if can_veto:
345     flags = flags | wxCANCEL
346 jan 374 result = self.RunMessageBox(_("Exit"),
347     _("The session has been modified."
348 bh 58 " Do you want to save it?"),
349     flags)
350     if result == wxID_YES:
351     self.SaveSession()
352     else:
353     result = wxID_NO
354     return result
355    
356 jonathan 487 def prepare_new_session(self):
357     for d in self.dialogs.values():
358     if not isinstance(d, tree.SessionTreeView):
359 jonathan 502 d.Close()
360 jonathan 487
361 bh 6 def NewSession(self):
362 bh 58 self.save_modified_session()
363 jonathan 487 self.prepare_new_session()
364 bh 227 self.application.SetSession(create_empty_session())
365 bh 6
366     def OpenSession(self):
367 bh 58 self.save_modified_session()
368 jonathan 879 dlg = wxFileDialog(self, _("Open Session"), ".", "",
369     "Thuban Session File (*.thuban)|*.thuban", wxOPEN)
370 bh 6 if dlg.ShowModal() == wxID_OK:
371 jonathan 487 self.prepare_new_session()
372 bh 227 self.application.OpenSession(dlg.GetPath())
373 bh 6 dlg.Destroy()
374    
375     def SaveSession(self):
376 bh 227 if self.application.session.filename == None:
377 jan 102 self.SaveSessionAs()
378 jonathan 487 else:
379     self.application.SaveSession()
380 bh 6
381     def SaveSessionAs(self):
382 jonathan 431 dlg = wxFileDialog(self, _("Save Session As"), ".", "",
383 jonathan 879 "Thuban Session File (*.thuban)|*.thuban",
384     wxSAVE|wxOVERWRITE_PROMPT)
385 bh 6 if dlg.ShowModal() == wxID_OK:
386 bh 227 self.application.session.SetFilename(dlg.GetPath())
387     self.application.SaveSession()
388 bh 6 dlg.Destroy()
389    
390     def Exit(self):
391 jonathan 621 self.Close(False)
392 bh 6
393 jonathan 580 def _OnClose(self, event):
394 bh 58 result = self.save_modified_session(can_veto = event.CanVeto())
395     if result == wxID_CANCEL:
396 bh 6 event.Veto()
397     else:
398 bh 307 # FIXME: it would be better to tie the unsubscription to
399     # wx's destroy event, but that isn't implemented for wxGTK
400     # yet.
401     self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
402 jonathan 580 DockFrame._OnClose(self, event)
403 bh 6 self.Destroy()
404    
405     def SetMap(self, map):
406     self.canvas.SetMap(map)
407 jonathan 653 self.__SetTitle(map.Title())
408 bh 6
409 jonathan 768 dialog = self.FindRegisteredDock("legend")
410     if dialog is not None:
411     dialog.GetPanel().SetMap(self.Map())
412    
413 bh 310 def Map(self):
414     """Return the map displayed by this mainwindow"""
415 jonathan 563
416 bh 310 return self.canvas.Map()
417    
418 bh 622 def ToggleSessionTree(self):
419     """If the session tree is shown close it otherwise create a new tree"""
420 bh 37 name = "session_tree"
421     dialog = self.get_open_dialog(name)
422     if dialog is None:
423 bh 227 dialog = tree.SessionTreeView(self, self.application, name)
424 bh 37 self.add_dialog(name, dialog)
425 jonathan 512 dialog.Show(True)
426 bh 37 else:
427 bh 622 dialog.Close()
428 bh 37
429 bh 622 def SessionTreeShown(self):
430     """Return true iff the session tree is currently shown"""
431     return self.get_open_dialog("session_tree") is not None
432 jonathan 517
433 bh 6 def About(self):
434 jan 374 self.RunMessageBox(_("About"),
435 jonathan 517 _("Thuban v%s\n"
436     #"Build Date: %s\n"
437     "\n"
438     "Thuban is a program for\n"
439 bh 20 "exploring geographic data.\n"
440 jan 374 "Copyright (C) 2001-2003 Intevation GmbH.\n"
441 jonathan 517 "Thuban is licensed under the GNU GPL"
442     % __ThubanVersion__), #__BuildDate__)),
443 bh 20 wxOK | wxICON_INFORMATION)
444 bh 6
445     def AddLayer(self):
446 jan 374 dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
447 bh 6 wxOPEN)
448     if dlg.ShowModal() == wxID_OK:
449     filename = dlg.GetPath()
450     title = os.path.splitext(os.path.basename(filename))[0]
451 bh 723 store = self.application.Session().OpenShapefile(filename)
452     layer = Layer(title, store)
453 bh 18 map = self.canvas.Map()
454     has_layers = map.HasLayers()
455 bh 20 try:
456     map.AddLayer(layer)
457     except IOError:
458     # the layer couldn't be opened
459 jan 374 self.RunMessageBox(_("Add Layer"),
460     _("Can't open the file '%s'.") % filename)
461 bh 20 else:
462     if not has_layers:
463 bh 535 # if we're adding a layer to an empty map, fit the
464 bh 20 # new map to the window
465     self.canvas.FitMapToWindow()
466 bh 6 dlg.Destroy()
467    
468     def RemoveLayer(self):
469     layer = self.current_layer()
470     if layer is not None:
471     self.canvas.Map().RemoveLayer(layer)
472    
473 bh 299 def CanRemoveLayer(self):
474     """Return true if the currently selected layer can be deleted.
475    
476 jonathan 621 If no layer is selected return False.
477 bh 299
478     The return value of this method determines whether the remove
479     layer command is sensitive in menu.
480     """
481     layer = self.current_layer()
482     if layer is not None:
483     return self.canvas.Map().CanRemoveLayer(layer)
484 jonathan 621 return False
485 bh 299
486 bh 6 def RaiseLayer(self):
487     layer = self.current_layer()
488     if layer is not None:
489     self.canvas.Map().RaiseLayer(layer)
490 bh 222
491 bh 6 def LowerLayer(self):
492     layer = self.current_layer()
493     if layer is not None:
494     self.canvas.Map().LowerLayer(layer)
495    
496     def current_layer(self):
497     """Return the currently selected layer.
498    
499     If no layer is selected, return None
500     """
501 bh 535 return self.canvas.SelectedLayer()
502 bh 6
503     def has_selected_layer(self):
504     """Return true if a layer is currently selected"""
505 bh 535 return self.canvas.HasSelectedLayer()
506 bh 6
507 jonathan 829 def has_selected_shapes(self):
508     """Return true if a shape is currently selected"""
509     return self.canvas.HasSelectedShapes()
510    
511 bh 6 def HideLayer(self):
512     layer = self.current_layer()
513     if layer is not None:
514     layer.SetVisible(0)
515    
516     def ShowLayer(self):
517     layer = self.current_layer()
518     if layer is not None:
519     layer.SetVisible(1)
520    
521     def LayerShowTable(self):
522     layer = self.current_layer()
523     if layer is not None:
524 bh 31 table = layer.table
525     name = "table_view" + str(id(table))
526     dialog = self.get_open_dialog(name)
527     if dialog is None:
528 bh 535 dialog = tableview.LayerTableFrame(self, name,
529     _("Table: %s") % layer.Title(),
530 bh 278 layer, table)
531 bh 31 self.add_dialog(name, dialog)
532     dialog.Show(true)
533     else:
534     # FIXME: bring dialog to front here
535     pass
536 bh 6
537 jonathan 729 def MapProjection(self):
538 bh 6
539 jonathan 729 name = "map_projection"
540 jonathan 713 dialog = self.get_open_dialog(name)
541    
542     if dialog is None:
543     map = self.canvas.Map()
544 jonathan 750 dialog = projdialog.ProjFrame(self, name,
545     _("Map Projection: %s") % map.Title(), map)
546 jonathan 713 self.add_dialog(name, dialog)
547     dialog.Show()
548     dialog.Raise()
549    
550 jonathan 729 def LayerProjection(self):
551    
552     layer = self.current_layer()
553    
554     name = "layer_projection" + str(id(layer))
555     dialog = self.get_open_dialog(name)
556    
557     if dialog is None:
558     map = self.canvas.Map()
559 jonathan 750 dialog = projdialog.ProjFrame(self, name,
560     _("Layer Projection: %s") % layer.Title(), layer)
561 jonathan 729 self.add_dialog(name, dialog)
562     dialog.Show()
563     dialog.Raise()
564    
565 jonathan 640 def LayerEditProperties(self):
566 jonathan 363
567 jonathan 487 #
568     # the menu option for this should only be available if there
569     # is a current layer, so we don't need to check if the
570     # current layer is None
571     #
572    
573     layer = self.current_layer()
574 jonathan 640 self.OpenLayerProperties(layer)
575 jonathan 550
576 jonathan 640 def OpenLayerProperties(self, layer, group = None):
577     name = "layer_properties" + str(id(layer))
578 jonathan 487 dialog = self.get_open_dialog(name)
579    
580     if dialog is None:
581 jonathan 633 dialog = Classifier(self, name, layer, group)
582 jonathan 487 self.add_dialog(name, dialog)
583     dialog.Show()
584 jonathan 573 dialog.Raise()
585 jonathan 487
586 jonathan 879 def LayerJoinTable(self):
587     print "LayerJoinTable"
588 jonathan 550
589 jonathan 879 def LayerUnjoinTable(self):
590     print "LayerUnjoinTable"
591    
592 jonathan 621 def ShowLegend(self):
593 bh 622 if not self.LegendShown():
594     self.ToggleLegend()
595    
596     def ToggleLegend(self):
597     """Show the legend if it's not shown otherwise hide it again"""
598 jonathan 550 name = "legend"
599 jonathan 573 dialog = self.FindRegisteredDock(name)
600 jonathan 550
601     if dialog is None:
602 jonathan 640 dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
603 jonathan 573 legend.LegendPanel(dialog, None, self)
604 jonathan 580 dialog.Dock()
605 bh 622 dialog.GetPanel().SetMap(self.Map())
606     dialog.Show()
607     else:
608     dialog.Show(not dialog.IsShown())
609 jonathan 563
610 bh 622 def LegendShown(self):
611     """Return true iff the legend is currently open"""
612     dialog = self.FindRegisteredDock("legend")
613     return dialog is not None and dialog.IsShown()
614 jonathan 563
615 jonathan 879 def TableOpen(self):
616     print "TableOpen"
617     dlg = wxFileDialog(self, _("Open Table"), ".", "",
618     "DBF Files (*.dbf)|*.dbf|" +
619     "CSV Files (*.csv)|*.csv|" +
620     "All Files (*.*)|*.*",
621     wxOPEN)
622     if dlg.ShowModal() == wxID_OK:
623     #self.application.session.OpenTable(dlg.GetPath())
624     pass
625    
626     dlg.Destroy()
627    
628     def TableClose(self):
629     print "TableClose"
630    
631     def TableShow(self):
632     print "TableShow"
633    
634     def TableHide(self):
635     print "TableHide"
636    
637     def TableJoin(self):
638     print "TableJoin"
639     dlg = JoinDialog(self, _("Join Tables"), self.application.session)
640     if dlg.ShowModal() == wxID_OK:
641     print "OK"
642    
643 bh 6 def ZoomInTool(self):
644     self.canvas.ZoomInTool()
645    
646     def ZoomOutTool(self):
647     self.canvas.ZoomOutTool()
648    
649     def PanTool(self):
650     self.canvas.PanTool()
651    
652     def IdentifyTool(self):
653     self.canvas.IdentifyTool()
654 bh 49 self.identify_view_on_demand(None, None)
655 bh 6
656     def LabelTool(self):
657     self.canvas.LabelTool()
658    
659     def FullExtent(self):
660     self.canvas.FitMapToWindow()
661    
662 jonathan 821 def FullLayerExtent(self):
663     self.canvas.FitLayerToWindow(self.current_layer())
664    
665 jonathan 829 def FullSelectionExtent(self):
666     self.canvas.FitSelectedToWindow()
667    
668 bh 6 def PrintMap(self):
669     self.canvas.Print()
670    
671 jonathan 653 def RenameMap(self):
672     dlg = wxTextEntryDialog(self, "Map Title: ", "Rename Map",
673     self.Map().Title())
674     if dlg.ShowModal() == wxID_OK:
675     title = dlg.GetValue()
676     if title != "":
677     self.Map().SetTitle(title)
678     self.__SetTitle(title)
679    
680     dlg.Destroy()
681    
682 bh 535 def identify_view_on_demand(self, layer, shapes):
683 bh 787 """Subscribed to the canvas' SHAPES_SELECTED message
684    
685     If the current tool is the identify tool, at least one shape is
686     selected and the identify dialog is not shown, show the dialog.
687     """
688     # If the selection has become empty we don't need to do
689     # anything. Otherwise it could happen that the dialog was popped
690     # up when the selection became empty, e.g. when a new selection
691     # is opened while the identify tool is active and dialog had
692     # been closed
693     if not shapes:
694     return
695    
696 bh 31 name = "identify_view"
697     if self.canvas.CurrentTool() == "IdentifyTool":
698     if not self.dialog_open(name):
699 bh 535 dialog = identifyview.IdentifyView(self, name)
700 bh 31 self.add_dialog(name, dialog)
701 jonathan 563 dialog.Show(True)
702 bh 31 else:
703 bh 33 # FIXME: bring dialog to front?
704 bh 31 pass
705 bh 6
706 jonathan 653 def __SetTitle(self, title):
707     self.SetTitle("Thuban - " + title)
708    
709 bh 6 #
710     # Define all the commands available in the main window
711     #
712    
713    
714     # Helper functions to define common command implementations
715     def call_method(context, methodname, *args):
716 bh 222 """Call the mainwindow's method methodname with args *args"""
717     apply(getattr(context.mainwindow, methodname), args)
718 bh 6
719 jan 110 def _method_command(name, title, method, helptext = "",
720 bh 622 icon = "", sensitive = None, checked = None):
721 bh 222 """Add a command implemented by a method of the mainwindow object"""
722 bh 6 registry.Add(Command(name, title, call_method, args=(method,),
723 jan 110 helptext = helptext, icon = icon,
724 bh 622 sensitive = sensitive, checked = checked))
725 jan 110
726 bh 270 def make_check_current_tool(toolname):
727     """Return a function that tests if the currently active tool is toolname
728    
729     The returned function can be called with the context and returns
730     true iff the currently active tool's name is toolname. It's directly
731     usable as the 'checked' callback of a command.
732     """
733     def check_current_tool(context, name=toolname):
734     return context.mainwindow.canvas.CurrentTool() == name
735     return check_current_tool
736    
737 bh 6 def _tool_command(name, title, method, toolname, helptext = "",
738 bh 310 icon = "", sensitive = None):
739 bh 6 """Add a tool command"""
740 bh 357 registry.Add(ToolCommand(name, title, call_method, args=(method,),
741     helptext = helptext, icon = icon,
742     checked = make_check_current_tool(toolname),
743     sensitive = sensitive))
744 bh 6
745     def _has_selected_layer(context):
746     """Return true if a layer is selected in the context"""
747 bh 222 return context.mainwindow.has_selected_layer()
748 bh 6
749 jonathan 829 def _has_selected_shapes(context):
750     """Return true if a layer is selected in the context"""
751     return context.mainwindow.has_selected_shapes()
752    
753 bh 299 def _can_remove_layer(context):
754     return context.mainwindow.CanRemoveLayer()
755    
756 jan 264 def _has_tree_window_shown(context):
757     """Return true if the tree window is shown"""
758 bh 622 return context.mainwindow.SessionTreeShown()
759 jan 264
760 bh 310 def _has_visible_map(context):
761     """Return true iff theres a visible map in the mainwindow.
762    
763     A visible map is a map with at least one visible layer."""
764     map = context.mainwindow.Map()
765     if map is not None:
766     for layer in map.Layers():
767     if layer.Visible():
768     return 1
769     return 0
770    
771 jonathan 550 def _has_legend_shown(context):
772     """Return true if the legend window is shown"""
773 bh 622 return context.mainwindow.LegendShown()
774 bh 310
775 jonathan 550
776 bh 6 # File menu
777 jan 374 _method_command("new_session", _("&New Session"), "NewSession")
778 jonathan 815 _method_command("open_session", _("&Open Session..."), "OpenSession")
779 jan 374 _method_command("save_session", _("&Save Session"), "SaveSession")
780 jonathan 815 _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs")
781 bh 622 _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
782     checked = _has_tree_window_shown)
783     _method_command("toggle_legend", _("Legend"), "ToggleLegend",
784     checked = _has_legend_shown)
785 jan 374 _method_command("exit", _("E&xit"), "Exit")
786 bh 6
787     # Help menu
788 jonathan 815 _method_command("help_about", _("&About..."), "About")
789 bh 6
790    
791     # Map menu
792 jonathan 815 _method_command("map_projection", _("Pro&jection..."), "MapProjection")
793 bh 6
794 jan 374 _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
795     helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
796 bh 310 sensitive = _has_visible_map)
797 jan 374 _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
798     helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
799 bh 310 sensitive = _has_visible_map)
800 jan 374 _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
801     helptext = _("Switch to map-mode 'pan'"), icon = "pan",
802 bh 310 sensitive = _has_visible_map)
803 jan 374 _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
804     "IdentifyTool",
805     helptext = _("Switch to map-mode 'identify'"), icon = "identify",
806 bh 310 sensitive = _has_visible_map)
807 jan 374 _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
808     helptext = _("Add/Remove labels"), icon = "label",
809 bh 310 sensitive = _has_visible_map)
810 jan 374 _method_command("map_full_extent", _("&Full extent"), "FullExtent",
811     helptext = _("Full Extent"), icon = "fullextent",
812 bh 310 sensitive = _has_visible_map)
813 jonathan 821 _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
814 jonathan 829 helptext = _("Full Layer Extent"), icon = "fulllayerextent",
815 jonathan 821 sensitive = _has_selected_layer)
816 jonathan 829 _method_command("selected_full_extent", _("&Full selection extent"), "FullSelectionExtent",
817     helptext = _("Full Selection Extent"), icon = "fullselextent",
818     sensitive = _has_selected_shapes)
819 jan 374 _method_command("map_print", _("Prin&t"), "PrintMap",
820     helptext = _("Print the map"))
821 jonathan 815 _method_command("map_rename", _("&Rename..."), "RenameMap",
822 jonathan 653 helptext = _("Rename the map"))
823 jonathan 815 _method_command("layer_add", _("&Add Layer..."), "AddLayer",
824 jan 374 helptext = _("Add a new layer to active map"))
825     _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
826     helptext = _("Remove selected layer(s)"),
827 bh 299 sensitive = _can_remove_layer)
828 jonathan 729
829     # Layer menu
830 jonathan 815 _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
831 jonathan 729 sensitive = _has_selected_layer)
832 jan 374 _method_command("layer_raise", _("&Raise"), "RaiseLayer",
833     helptext = _("Raise selected layer(s)"),
834 bh 6 sensitive = _has_selected_layer)
835 jan 374 _method_command("layer_lower", _("&Lower"), "LowerLayer",
836     helptext = _("Lower selected layer(s)"),
837 bh 6 sensitive = _has_selected_layer)
838 jan 374 _method_command("layer_show", _("&Show"), "ShowLayer",
839     helptext = _("Make selected layer(s) visible"),
840 bh 6 sensitive = _has_selected_layer)
841 jan 374 _method_command("layer_hide", _("&Hide"), "HideLayer",
842     helptext = _("Make selected layer(s) unvisible"),
843 bh 6 sensitive = _has_selected_layer)
844 jan 374 _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
845     helptext = _("Show the selected layer's table"),
846 bh 6 sensitive = _has_selected_layer)
847 jonathan 815 _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
848 jonathan 363 sensitive = _has_selected_layer)
849 jonathan 879 _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
850     sensitive = _has_selected_layer)
851     _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
852     sensitive = _has_selected_layer)
853 bh 188
854 jonathan 879 # Table menu
855     _method_command("table_open", _("&Open..."), "TableOpen")
856     _method_command("table_close", _("&Close"), "TableClose")
857     _method_command("table_show", _("&Show"), "TableShow")
858     _method_command("table_hide", _("&Hide"), "TableHide")
859     _method_command("table_join", _("&Join..."), "TableJoin")
860    
861 bh 188 # the menu structure
862     main_menu = Menu("<main>", "<main>",
863 jan 374 [Menu("file", _("&File"),
864 bh 188 ["new_session", "open_session", None,
865     "save_session", "save_session_as", None,
866 bh 624 "toggle_session_tree", None,
867 bh 188 "exit"]),
868 jan 374 Menu("map", _("&Map"),
869 jonathan 796 ["layer_add", "layer_remove", "map_rename",
870 bh 188 None,
871     "map_projection",
872     None,
873     "map_zoom_in_tool", "map_zoom_out_tool",
874 jonathan 829 "map_pan_tool",
875     "map_full_extent",
876     "layer_full_extent",
877     "selected_full_extent",
878 bh 188 None,
879 jonathan 815 "map_identify_tool", "map_label_tool",
880 bh 188 None,
881 bh 624 "toggle_legend",
882     None,
883 jonathan 796 "map_print"]),
884 jan 374 Menu("layer", _("&Layer"),
885 jonathan 640 ["layer_raise", "layer_lower",
886 bh 188 None,
887     "layer_show", "layer_hide",
888     None,
889 jonathan 879 "layer_projection",
890     None,
891 jonathan 363 "layer_show_table",
892 jonathan 879 "layer_jointable",
893     "layer_unjointable",
894 jonathan 363 None,
895 jonathan 815 "layer_properties"]),
896 jonathan 879 Menu("table", _("&Table"),
897     ["table_open", "table_close",
898     None,
899     "table_show", "table_hide",
900     None,
901     "table_join"]),
902 jan 374 Menu("help", _("&Help"),
903 bh 188 ["help_about"])])
904 bh 191
905     # the main toolbar
906    
907     main_toolbar = Menu("<toolbar>", "<toolbar>",
908 frank 351 ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
909 jonathan 829 "map_full_extent",
910     "layer_full_extent",
911     "selected_full_extent",
912     None,
913 frank 351 "map_identify_tool", "map_label_tool"])

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26