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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1001 - (show annotations)
Thu May 22 19:40:27 2003 UTC (21 years, 9 months ago) by frank
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 35253 byte(s)
(MainWindow.TableJoin): Removed print.

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