/[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 879 - (show 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 # Copyright (C) 2001, 2002, 2003 by Intevation GmbH
2 # 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 __ThubanVersion__ = "0.2" #"$THUBAN_0_2$"
16 #__BuildDate__ = "$Date$"
17
18 import os
19
20 from wxPython.wx import *
21
22 import Thuban
23 from Thuban import _
24 from Thuban.Model.session import create_empty_session
25 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 from Thuban.UI.classifier import Classifier
34 import legend
35 from menu import Menu
36
37 from context import Context
38 from command import registry, Command, ToolCommand
39 from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION
40
41 from Thuban.UI.dock import DockFrame
42 from Thuban.UI.join import JoinDialog
43
44 import resource
45
46 import projdialog
47
48
49
50 class MainWindow(DockFrame):
51
52 # 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 "SelectedShapes": "canvas",
65 }
66
67 def __init__(self, parent, ID, title, application, interactor,
68 initial_message = None, size = wxSize(-1, -1)):
69 DockFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
70 #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
71
72 self.application = application
73
74 self.CreateStatusBar()
75 if initial_message:
76 self.SetStatusText(initial_message)
77
78 self.identify_view = None
79
80 self.init_ids()
81
82 # creat the menubar from the main_menu description
83 self.SetMenuBar(self.build_menu_bar(main_menu))
84
85 # Similarly, create the toolbar from main_toolbar
86 toolbar = self.build_toolbar(main_toolbar)
87 # call Realize to make sure that the tools appear.
88 toolbar.Realize()
89
90
91 # Create the map canvas
92 canvas = view.MapCanvas(self, -1)
93 canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
94 canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
95 self.canvas = canvas
96
97 self.SetMainWindow(self.canvas)
98
99 self.SetAutoLayout(True)
100
101 self.init_dialogs()
102
103 EVT_CLOSE(self, self._OnClose)
104
105 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 def init_ids(self):
137 """Initialize the ids"""
138 self.current_id = 6000
139 self.id_to_name = {}
140 self.name_to_id = {}
141 self.events_bound = {}
142
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
155 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 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 """Return a wxMenu built from the menu description menudesc"""
175 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 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 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 self.bind_command_events(command, ID)
229 else:
230 print _("Unknown command %s") % name
231
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 bitmap = resource.GetBitmapResource(command.Icon(),
246 wxBITMAP_TYPE_XPM)
247 toolbar.AddTool(ID, bitmap,
248 shortHelpString = command.HelpText(),
249 isToggle = command.IsCheckCommand())
250 self.bind_command_events(command, ID)
251 else:
252 print _("Unknown command %s") % name
253
254 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 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 command.Execute(self.Context())
264 else:
265 print _("Unknown command ID %d") % event.GetId()
266
267 def update_command_ui(self, event):
268 #print "update_command_ui", self.id_to_name[event.GetId()]
269 context = self.Context()
270 command = registry.Command(self.id_to_name[event.GetId()])
271 if command is not None:
272 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 event.SetText(command.DynText(context))
283 if command.IsCheckCommand():
284 event.Check(command.Checked(context))
285
286 def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
287 """Run a modal message box with the given text, title and flags
288 and return the result"""
289 dlg = wxMessageDialog(self, text, title, flags)
290 dlg.CenterOnParent()
291 result = dlg.ShowModal()
292 dlg.Destroy()
293 return result
294
295 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 raise RuntimeError(_("The Dialog named %s is already open") % name)
305 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 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 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 self.SetStatusText(text)
332
333 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 if self.application.session.WasModified():
343 flags = wxYES_NO | wxICON_QUESTION
344 if can_veto:
345 flags = flags | wxCANCEL
346 result = self.RunMessageBox(_("Exit"),
347 _("The session has been modified."
348 " 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 def prepare_new_session(self):
357 for d in self.dialogs.values():
358 if not isinstance(d, tree.SessionTreeView):
359 d.Close()
360
361 def NewSession(self):
362 self.save_modified_session()
363 self.prepare_new_session()
364 self.application.SetSession(create_empty_session())
365
366 def OpenSession(self):
367 self.save_modified_session()
368 dlg = wxFileDialog(self, _("Open Session"), ".", "",
369 "Thuban Session File (*.thuban)|*.thuban", wxOPEN)
370 if dlg.ShowModal() == wxID_OK:
371 self.prepare_new_session()
372 self.application.OpenSession(dlg.GetPath())
373 dlg.Destroy()
374
375 def SaveSession(self):
376 if self.application.session.filename == None:
377 self.SaveSessionAs()
378 else:
379 self.application.SaveSession()
380
381 def SaveSessionAs(self):
382 dlg = wxFileDialog(self, _("Save Session As"), ".", "",
383 "Thuban Session File (*.thuban)|*.thuban",
384 wxSAVE|wxOVERWRITE_PROMPT)
385 if dlg.ShowModal() == wxID_OK:
386 self.application.session.SetFilename(dlg.GetPath())
387 self.application.SaveSession()
388 dlg.Destroy()
389
390 def Exit(self):
391 self.Close(False)
392
393 def _OnClose(self, event):
394 result = self.save_modified_session(can_veto = event.CanVeto())
395 if result == wxID_CANCEL:
396 event.Veto()
397 else:
398 # 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 DockFrame._OnClose(self, event)
403 self.Destroy()
404
405 def SetMap(self, map):
406 self.canvas.SetMap(map)
407 self.__SetTitle(map.Title())
408
409 dialog = self.FindRegisteredDock("legend")
410 if dialog is not None:
411 dialog.GetPanel().SetMap(self.Map())
412
413 def Map(self):
414 """Return the map displayed by this mainwindow"""
415
416 return self.canvas.Map()
417
418 def ToggleSessionTree(self):
419 """If the session tree is shown close it otherwise create a new tree"""
420 name = "session_tree"
421 dialog = self.get_open_dialog(name)
422 if dialog is None:
423 dialog = tree.SessionTreeView(self, self.application, name)
424 self.add_dialog(name, dialog)
425 dialog.Show(True)
426 else:
427 dialog.Close()
428
429 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
433 def About(self):
434 self.RunMessageBox(_("About"),
435 _("Thuban v%s\n"
436 #"Build Date: %s\n"
437 "\n"
438 "Thuban is a program for\n"
439 "exploring geographic data.\n"
440 "Copyright (C) 2001-2003 Intevation GmbH.\n"
441 "Thuban is licensed under the GNU GPL"
442 % __ThubanVersion__), #__BuildDate__)),
443 wxOK | wxICON_INFORMATION)
444
445 def AddLayer(self):
446 dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
447 wxOPEN)
448 if dlg.ShowModal() == wxID_OK:
449 filename = dlg.GetPath()
450 title = os.path.splitext(os.path.basename(filename))[0]
451 store = self.application.Session().OpenShapefile(filename)
452 layer = Layer(title, store)
453 map = self.canvas.Map()
454 has_layers = map.HasLayers()
455 try:
456 map.AddLayer(layer)
457 except IOError:
458 # the layer couldn't be opened
459 self.RunMessageBox(_("Add Layer"),
460 _("Can't open the file '%s'.") % filename)
461 else:
462 if not has_layers:
463 # if we're adding a layer to an empty map, fit the
464 # new map to the window
465 self.canvas.FitMapToWindow()
466 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 def CanRemoveLayer(self):
474 """Return true if the currently selected layer can be deleted.
475
476 If no layer is selected return False.
477
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 return False
485
486 def RaiseLayer(self):
487 layer = self.current_layer()
488 if layer is not None:
489 self.canvas.Map().RaiseLayer(layer)
490
491 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 return self.canvas.SelectedLayer()
502
503 def has_selected_layer(self):
504 """Return true if a layer is currently selected"""
505 return self.canvas.HasSelectedLayer()
506
507 def has_selected_shapes(self):
508 """Return true if a shape is currently selected"""
509 return self.canvas.HasSelectedShapes()
510
511 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 table = layer.table
525 name = "table_view" + str(id(table))
526 dialog = self.get_open_dialog(name)
527 if dialog is None:
528 dialog = tableview.LayerTableFrame(self, name,
529 _("Table: %s") % layer.Title(),
530 layer, table)
531 self.add_dialog(name, dialog)
532 dialog.Show(true)
533 else:
534 # FIXME: bring dialog to front here
535 pass
536
537 def MapProjection(self):
538
539 name = "map_projection"
540 dialog = self.get_open_dialog(name)
541
542 if dialog is None:
543 map = self.canvas.Map()
544 dialog = projdialog.ProjFrame(self, name,
545 _("Map Projection: %s") % map.Title(), map)
546 self.add_dialog(name, dialog)
547 dialog.Show()
548 dialog.Raise()
549
550 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 dialog = projdialog.ProjFrame(self, name,
560 _("Layer Projection: %s") % layer.Title(), layer)
561 self.add_dialog(name, dialog)
562 dialog.Show()
563 dialog.Raise()
564
565 def LayerEditProperties(self):
566
567 #
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 self.OpenLayerProperties(layer)
575
576 def OpenLayerProperties(self, layer, group = None):
577 name = "layer_properties" + str(id(layer))
578 dialog = self.get_open_dialog(name)
579
580 if dialog is None:
581 dialog = Classifier(self, name, layer, group)
582 self.add_dialog(name, dialog)
583 dialog.Show()
584 dialog.Raise()
585
586 def LayerJoinTable(self):
587 print "LayerJoinTable"
588
589 def LayerUnjoinTable(self):
590 print "LayerUnjoinTable"
591
592 def ShowLegend(self):
593 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 name = "legend"
599 dialog = self.FindRegisteredDock(name)
600
601 if dialog is None:
602 dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
603 legend.LegendPanel(dialog, None, self)
604 dialog.Dock()
605 dialog.GetPanel().SetMap(self.Map())
606 dialog.Show()
607 else:
608 dialog.Show(not dialog.IsShown())
609
610 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
615 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 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 self.identify_view_on_demand(None, None)
655
656 def LabelTool(self):
657 self.canvas.LabelTool()
658
659 def FullExtent(self):
660 self.canvas.FitMapToWindow()
661
662 def FullLayerExtent(self):
663 self.canvas.FitLayerToWindow(self.current_layer())
664
665 def FullSelectionExtent(self):
666 self.canvas.FitSelectedToWindow()
667
668 def PrintMap(self):
669 self.canvas.Print()
670
671 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 def identify_view_on_demand(self, layer, shapes):
683 """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 name = "identify_view"
697 if self.canvas.CurrentTool() == "IdentifyTool":
698 if not self.dialog_open(name):
699 dialog = identifyview.IdentifyView(self, name)
700 self.add_dialog(name, dialog)
701 dialog.Show(True)
702 else:
703 # FIXME: bring dialog to front?
704 pass
705
706 def __SetTitle(self, title):
707 self.SetTitle("Thuban - " + title)
708
709 #
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 """Call the mainwindow's method methodname with args *args"""
717 apply(getattr(context.mainwindow, methodname), args)
718
719 def _method_command(name, title, method, helptext = "",
720 icon = "", sensitive = None, checked = None):
721 """Add a command implemented by a method of the mainwindow object"""
722 registry.Add(Command(name, title, call_method, args=(method,),
723 helptext = helptext, icon = icon,
724 sensitive = sensitive, checked = checked))
725
726 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 def _tool_command(name, title, method, toolname, helptext = "",
738 icon = "", sensitive = None):
739 """Add a tool command"""
740 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
745 def _has_selected_layer(context):
746 """Return true if a layer is selected in the context"""
747 return context.mainwindow.has_selected_layer()
748
749 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 def _can_remove_layer(context):
754 return context.mainwindow.CanRemoveLayer()
755
756 def _has_tree_window_shown(context):
757 """Return true if the tree window is shown"""
758 return context.mainwindow.SessionTreeShown()
759
760 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 def _has_legend_shown(context):
772 """Return true if the legend window is shown"""
773 return context.mainwindow.LegendShown()
774
775
776 # File menu
777 _method_command("new_session", _("&New Session"), "NewSession")
778 _method_command("open_session", _("&Open Session..."), "OpenSession")
779 _method_command("save_session", _("&Save Session"), "SaveSession")
780 _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs")
781 _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 _method_command("exit", _("E&xit"), "Exit")
786
787 # Help menu
788 _method_command("help_about", _("&About..."), "About")
789
790
791 # Map menu
792 _method_command("map_projection", _("Pro&jection..."), "MapProjection")
793
794 _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
795 helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
796 sensitive = _has_visible_map)
797 _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
798 helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
799 sensitive = _has_visible_map)
800 _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
801 helptext = _("Switch to map-mode 'pan'"), icon = "pan",
802 sensitive = _has_visible_map)
803 _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
804 "IdentifyTool",
805 helptext = _("Switch to map-mode 'identify'"), icon = "identify",
806 sensitive = _has_visible_map)
807 _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
808 helptext = _("Add/Remove labels"), icon = "label",
809 sensitive = _has_visible_map)
810 _method_command("map_full_extent", _("&Full extent"), "FullExtent",
811 helptext = _("Full Extent"), icon = "fullextent",
812 sensitive = _has_visible_map)
813 _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
814 helptext = _("Full Layer Extent"), icon = "fulllayerextent",
815 sensitive = _has_selected_layer)
816 _method_command("selected_full_extent", _("&Full selection extent"), "FullSelectionExtent",
817 helptext = _("Full Selection Extent"), icon = "fullselextent",
818 sensitive = _has_selected_shapes)
819 _method_command("map_print", _("Prin&t"), "PrintMap",
820 helptext = _("Print the map"))
821 _method_command("map_rename", _("&Rename..."), "RenameMap",
822 helptext = _("Rename the map"))
823 _method_command("layer_add", _("&Add Layer..."), "AddLayer",
824 helptext = _("Add a new layer to active map"))
825 _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
826 helptext = _("Remove selected layer(s)"),
827 sensitive = _can_remove_layer)
828
829 # Layer menu
830 _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
831 sensitive = _has_selected_layer)
832 _method_command("layer_raise", _("&Raise"), "RaiseLayer",
833 helptext = _("Raise selected layer(s)"),
834 sensitive = _has_selected_layer)
835 _method_command("layer_lower", _("&Lower"), "LowerLayer",
836 helptext = _("Lower selected layer(s)"),
837 sensitive = _has_selected_layer)
838 _method_command("layer_show", _("&Show"), "ShowLayer",
839 helptext = _("Make selected layer(s) visible"),
840 sensitive = _has_selected_layer)
841 _method_command("layer_hide", _("&Hide"), "HideLayer",
842 helptext = _("Make selected layer(s) unvisible"),
843 sensitive = _has_selected_layer)
844 _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
845 helptext = _("Show the selected layer's table"),
846 sensitive = _has_selected_layer)
847 _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
848 sensitive = _has_selected_layer)
849 _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
854 # 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 # the menu structure
862 main_menu = Menu("<main>", "<main>",
863 [Menu("file", _("&File"),
864 ["new_session", "open_session", None,
865 "save_session", "save_session_as", None,
866 "toggle_session_tree", None,
867 "exit"]),
868 Menu("map", _("&Map"),
869 ["layer_add", "layer_remove", "map_rename",
870 None,
871 "map_projection",
872 None,
873 "map_zoom_in_tool", "map_zoom_out_tool",
874 "map_pan_tool",
875 "map_full_extent",
876 "layer_full_extent",
877 "selected_full_extent",
878 None,
879 "map_identify_tool", "map_label_tool",
880 None,
881 "toggle_legend",
882 None,
883 "map_print"]),
884 Menu("layer", _("&Layer"),
885 ["layer_raise", "layer_lower",
886 None,
887 "layer_show", "layer_hide",
888 None,
889 "layer_projection",
890 None,
891 "layer_show_table",
892 "layer_jointable",
893 "layer_unjointable",
894 None,
895 "layer_properties"]),
896 Menu("table", _("&Table"),
897 ["table_open", "table_close",
898 None,
899 "table_show", "table_hide",
900 None,
901 "table_join"]),
902 Menu("help", _("&Help"),
903 ["help_about"])])
904
905 # the main toolbar
906
907 main_toolbar = Menu("<toolbar>", "<toolbar>",
908 ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
909 "map_full_extent",
910 "layer_full_extent",
911 "selected_full_extent",
912 None,
913 "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