/[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 923 - (show annotations)
Mon May 19 09:12:25 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: 34112 byte(s)
Extended version information: Display Thuban, wxPython and Python version.

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
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 self.save_modified_session()
367 self.prepare_new_session()
368 self.application.SetSession(create_empty_session())
369
370 def OpenSession(self):
371 self.save_modified_session()
372 dlg = wxFileDialog(self, _("Open Session"), ".", "",
373 "Thuban Session File (*.thuban)|*.thuban", wxOPEN)
374 if dlg.ShowModal() == wxID_OK:
375 self.prepare_new_session()
376 self.application.OpenSession(dlg.GetPath())
377 dlg.Destroy()
378
379 def SaveSession(self):
380 if self.application.session.filename == None:
381 self.SaveSessionAs()
382 else:
383 self.application.SaveSession()
384
385 def SaveSessionAs(self):
386 dlg = wxFileDialog(self, _("Save Session As"), ".", "",
387 "Thuban Session File (*.thuban)|*.thuban",
388 wxSAVE|wxOVERWRITE_PROMPT)
389 if dlg.ShowModal() == wxID_OK:
390 self.application.session.SetFilename(dlg.GetPath())
391 self.application.SaveSession()
392 dlg.Destroy()
393
394 def Exit(self):
395 self.Close(False)
396
397 def _OnClose(self, event):
398 result = self.save_modified_session(can_veto = event.CanVeto())
399 if result == wxID_CANCEL:
400 event.Veto()
401 else:
402 # FIXME: it would be better to tie the unsubscription to
403 # wx's destroy event, but that isn't implemented for wxGTK
404 # yet.
405 self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
406 DockFrame._OnClose(self, event)
407 self.Destroy()
408
409 def SetMap(self, map):
410 self.canvas.SetMap(map)
411 self.__SetTitle(map.Title())
412
413 dialog = self.FindRegisteredDock("legend")
414 if dialog is not None:
415 dialog.GetPanel().SetMap(self.Map())
416
417 def Map(self):
418 """Return the map displayed by this mainwindow"""
419
420 return self.canvas.Map()
421
422 def ToggleSessionTree(self):
423 """If the session tree is shown close it otherwise create a new tree"""
424 name = "session_tree"
425 dialog = self.get_open_dialog(name)
426 if dialog is None:
427 dialog = tree.SessionTreeView(self, self.application, name)
428 self.add_dialog(name, dialog)
429 dialog.Show(True)
430 else:
431 dialog.Close()
432
433 def SessionTreeShown(self):
434 """Return true iff the session tree is currently shown"""
435 return self.get_open_dialog("session_tree") is not None
436
437 def About(self):
438 self.RunMessageBox(_("About"),
439 _("Thuban %s\n"
440 #"Build Date: %s\n"
441 "using:\n"
442 " %s\n"
443 " %s\n\n"
444 "Thuban is a program for\n"
445 "exploring geographic data.\n"
446 "Copyright (C) 2001-2003 Intevation GmbH.\n"
447 "Thuban is licensed under the GNU GPL"
448 % (Thuban.version.longversion,
449 "wxPython %s" % wxPython_version,
450 "Python %d.%d.%d" % sys.version_info[:3]
451 )),
452 # % __ThubanVersion__), #__BuildDate__)),
453 wxOK | wxICON_INFORMATION)
454
455 def AddLayer(self):
456 dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
457 wxOPEN)
458 if dlg.ShowModal() == wxID_OK:
459 filename = dlg.GetPath()
460 title = os.path.splitext(os.path.basename(filename))[0]
461 store = self.application.Session().OpenShapefile(filename)
462 layer = Layer(title, store)
463 map = self.canvas.Map()
464 has_layers = map.HasLayers()
465 try:
466 map.AddLayer(layer)
467 except IOError:
468 # the layer couldn't be opened
469 self.RunMessageBox(_("Add Layer"),
470 _("Can't open the file '%s'.") % filename)
471 else:
472 if not has_layers:
473 # if we're adding a layer to an empty map, fit the
474 # new map to the window
475 self.canvas.FitMapToWindow()
476 dlg.Destroy()
477
478 def RemoveLayer(self):
479 layer = self.current_layer()
480 if layer is not None:
481 self.canvas.Map().RemoveLayer(layer)
482
483 def CanRemoveLayer(self):
484 """Return true if the currently selected layer can be deleted.
485
486 If no layer is selected return False.
487
488 The return value of this method determines whether the remove
489 layer command is sensitive in menu.
490 """
491 layer = self.current_layer()
492 if layer is not None:
493 return self.canvas.Map().CanRemoveLayer(layer)
494 return False
495
496 def RaiseLayer(self):
497 layer = self.current_layer()
498 if layer is not None:
499 self.canvas.Map().RaiseLayer(layer)
500
501 def LowerLayer(self):
502 layer = self.current_layer()
503 if layer is not None:
504 self.canvas.Map().LowerLayer(layer)
505
506 def current_layer(self):
507 """Return the currently selected layer.
508
509 If no layer is selected, return None
510 """
511 return self.canvas.SelectedLayer()
512
513 def has_selected_layer(self):
514 """Return true if a layer is currently selected"""
515 return self.canvas.HasSelectedLayer()
516
517 def has_selected_shapes(self):
518 """Return true if a shape is currently selected"""
519 return self.canvas.HasSelectedShapes()
520
521 def HideLayer(self):
522 layer = self.current_layer()
523 if layer is not None:
524 layer.SetVisible(0)
525
526 def ShowLayer(self):
527 layer = self.current_layer()
528 if layer is not None:
529 layer.SetVisible(1)
530
531 def LayerShowTable(self):
532 layer = self.current_layer()
533 if layer is not None:
534 table = layer.table
535 name = "table_view" + str(id(table))
536 dialog = self.get_open_dialog(name)
537 if dialog is None:
538 dialog = tableview.LayerTableFrame(self, name,
539 _("Table: %s") % layer.Title(),
540 layer, table)
541 self.add_dialog(name, dialog)
542 dialog.Show(true)
543 else:
544 # FIXME: bring dialog to front here
545 pass
546
547 def MapProjection(self):
548
549 name = "map_projection"
550 dialog = self.get_open_dialog(name)
551
552 if dialog is None:
553 map = self.canvas.Map()
554 dialog = projdialog.ProjFrame(self, name,
555 _("Map Projection: %s") % map.Title(), map)
556 self.add_dialog(name, dialog)
557 dialog.Show()
558 dialog.Raise()
559
560 def LayerProjection(self):
561
562 layer = self.current_layer()
563
564 name = "layer_projection" + str(id(layer))
565 dialog = self.get_open_dialog(name)
566
567 if dialog is None:
568 map = self.canvas.Map()
569 dialog = projdialog.ProjFrame(self, name,
570 _("Layer Projection: %s") % layer.Title(), layer)
571 self.add_dialog(name, dialog)
572 dialog.Show()
573 dialog.Raise()
574
575 def LayerEditProperties(self):
576
577 #
578 # the menu option for this should only be available if there
579 # is a current layer, so we don't need to check if the
580 # current layer is None
581 #
582
583 layer = self.current_layer()
584 self.OpenLayerProperties(layer)
585
586 def OpenLayerProperties(self, layer, group = None):
587 name = "layer_properties" + str(id(layer))
588 dialog = self.get_open_dialog(name)
589
590 if dialog is None:
591 dialog = Classifier(self, name, layer, group)
592 self.add_dialog(name, dialog)
593 dialog.Show()
594 dialog.Raise()
595
596 def LayerJoinTable(self):
597 print "LayerJoinTable"
598
599 def LayerUnjoinTable(self):
600 print "LayerUnjoinTable"
601
602 def ShowLegend(self):
603 if not self.LegendShown():
604 self.ToggleLegend()
605
606 def ToggleLegend(self):
607 """Show the legend if it's not shown otherwise hide it again"""
608 name = "legend"
609 dialog = self.FindRegisteredDock(name)
610
611 if dialog is None:
612 dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
613 legend.LegendPanel(dialog, None, self)
614 dialog.Dock()
615 dialog.GetPanel().SetMap(self.Map())
616 dialog.Show()
617 else:
618 dialog.Show(not dialog.IsShown())
619
620 def LegendShown(self):
621 """Return true iff the legend is currently open"""
622 dialog = self.FindRegisteredDock("legend")
623 return dialog is not None and dialog.IsShown()
624
625 def TableOpen(self):
626 print "TableOpen"
627 dlg = wxFileDialog(self, _("Open Table"), ".", "",
628 "DBF Files (*.dbf)|*.dbf|" +
629 "CSV Files (*.csv)|*.csv|" +
630 "All Files (*.*)|*.*",
631 wxOPEN)
632 if dlg.ShowModal() == wxID_OK:
633 #self.application.session.OpenTable(dlg.GetPath())
634 pass
635
636 dlg.Destroy()
637
638 def TableClose(self):
639 print "TableClose"
640
641 def TableShow(self):
642 print "TableShow"
643
644 def TableHide(self):
645 print "TableHide"
646
647 def TableJoin(self):
648 print "TableJoin"
649 dlg = JoinDialog(self, _("Join Tables"), self.application.session)
650 if dlg.ShowModal() == wxID_OK:
651 print "OK"
652
653 def ZoomInTool(self):
654 self.canvas.ZoomInTool()
655
656 def ZoomOutTool(self):
657 self.canvas.ZoomOutTool()
658
659 def PanTool(self):
660 self.canvas.PanTool()
661
662 def IdentifyTool(self):
663 self.canvas.IdentifyTool()
664 self.identify_view_on_demand(None, None)
665
666 def LabelTool(self):
667 self.canvas.LabelTool()
668
669 def FullExtent(self):
670 self.canvas.FitMapToWindow()
671
672 def FullLayerExtent(self):
673 self.canvas.FitLayerToWindow(self.current_layer())
674
675 def FullSelectionExtent(self):
676 self.canvas.FitSelectedToWindow()
677
678 def ExportMap(self):
679 self.canvas.Export()
680
681 def PrintMap(self):
682 self.canvas.Print()
683
684 def RenameMap(self):
685 dlg = wxTextEntryDialog(self, "Map Title: ", "Rename Map",
686 self.Map().Title())
687 if dlg.ShowModal() == wxID_OK:
688 title = dlg.GetValue()
689 if title != "":
690 self.Map().SetTitle(title)
691 self.__SetTitle(title)
692
693 dlg.Destroy()
694
695 def identify_view_on_demand(self, layer, shapes):
696 """Subscribed to the canvas' SHAPES_SELECTED message
697
698 If the current tool is the identify tool, at least one shape is
699 selected and the identify dialog is not shown, show the dialog.
700 """
701 # If the selection has become empty we don't need to do
702 # anything. Otherwise it could happen that the dialog was popped
703 # up when the selection became empty, e.g. when a new selection
704 # is opened while the identify tool is active and dialog had
705 # been closed
706 if not shapes:
707 return
708
709 name = "identify_view"
710 if self.canvas.CurrentTool() == "IdentifyTool":
711 if not self.dialog_open(name):
712 dialog = identifyview.IdentifyView(self, name)
713 self.add_dialog(name, dialog)
714 dialog.Show(True)
715 else:
716 # FIXME: bring dialog to front?
717 pass
718
719 def __SetTitle(self, title):
720 self.SetTitle("Thuban - " + title)
721
722 #
723 # Define all the commands available in the main window
724 #
725
726
727 # Helper functions to define common command implementations
728 def call_method(context, methodname, *args):
729 """Call the mainwindow's method methodname with args *args"""
730 apply(getattr(context.mainwindow, methodname), args)
731
732 def _method_command(name, title, method, helptext = "",
733 icon = "", sensitive = None, checked = None):
734 """Add a command implemented by a method of the mainwindow object"""
735 registry.Add(Command(name, title, call_method, args=(method,),
736 helptext = helptext, icon = icon,
737 sensitive = sensitive, checked = checked))
738
739 def make_check_current_tool(toolname):
740 """Return a function that tests if the currently active tool is toolname
741
742 The returned function can be called with the context and returns
743 true iff the currently active tool's name is toolname. It's directly
744 usable as the 'checked' callback of a command.
745 """
746 def check_current_tool(context, name=toolname):
747 return context.mainwindow.canvas.CurrentTool() == name
748 return check_current_tool
749
750 def _tool_command(name, title, method, toolname, helptext = "",
751 icon = "", sensitive = None):
752 """Add a tool command"""
753 registry.Add(ToolCommand(name, title, call_method, args=(method,),
754 helptext = helptext, icon = icon,
755 checked = make_check_current_tool(toolname),
756 sensitive = sensitive))
757
758 def _has_selected_layer(context):
759 """Return true if a layer is selected in the context"""
760 return context.mainwindow.has_selected_layer()
761
762 def _has_selected_shapes(context):
763 """Return true if a layer is selected in the context"""
764 return context.mainwindow.has_selected_shapes()
765
766 def _can_remove_layer(context):
767 return context.mainwindow.CanRemoveLayer()
768
769 def _has_tree_window_shown(context):
770 """Return true if the tree window is shown"""
771 return context.mainwindow.SessionTreeShown()
772
773 def _has_visible_map(context):
774 """Return true iff theres a visible map in the mainwindow.
775
776 A visible map is a map with at least one visible layer."""
777 map = context.mainwindow.Map()
778 if map is not None:
779 for layer in map.Layers():
780 if layer.Visible():
781 return 1
782 return 0
783
784 def _has_legend_shown(context):
785 """Return true if the legend window is shown"""
786 return context.mainwindow.LegendShown()
787
788
789 # File menu
790 _method_command("new_session", _("&New Session"), "NewSession")
791 _method_command("open_session", _("&Open Session..."), "OpenSession")
792 _method_command("save_session", _("&Save Session"), "SaveSession")
793 _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs")
794 _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
795 checked = _has_tree_window_shown)
796 _method_command("toggle_legend", _("Legend"), "ToggleLegend",
797 checked = _has_legend_shown)
798 _method_command("exit", _("E&xit"), "Exit")
799
800 # Help menu
801 _method_command("help_about", _("&About..."), "About")
802
803
804 # Map menu
805 _method_command("map_projection", _("Pro&jection..."), "MapProjection")
806
807 _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
808 helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
809 sensitive = _has_visible_map)
810 _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
811 helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
812 sensitive = _has_visible_map)
813 _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
814 helptext = _("Switch to map-mode 'pan'"), icon = "pan",
815 sensitive = _has_visible_map)
816 _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
817 "IdentifyTool",
818 helptext = _("Switch to map-mode 'identify'"), icon = "identify",
819 sensitive = _has_visible_map)
820 _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
821 helptext = _("Add/Remove labels"), icon = "label",
822 sensitive = _has_visible_map)
823 _method_command("map_full_extent", _("&Full extent"), "FullExtent",
824 helptext = _("Full Extent"), icon = "fullextent",
825 sensitive = _has_visible_map)
826 _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
827 helptext = _("Full Layer Extent"), icon = "fulllayerextent",
828 sensitive = _has_selected_layer)
829 _method_command("selected_full_extent", _("&Full selection extent"), "FullSelectionExtent",
830 helptext = _("Full Selection Extent"), icon = "fullselextent",
831 sensitive = _has_selected_shapes)
832 _method_command("map_export", _("E&xport"), "ExportMap",
833 helptext = _("Export the map to file"))
834 _method_command("map_print", _("Prin&t"), "PrintMap",
835 helptext = _("Print the map"))
836 _method_command("map_rename", _("&Rename..."), "RenameMap",
837 helptext = _("Rename the map"))
838 _method_command("layer_add", _("&Add Layer..."), "AddLayer",
839 helptext = _("Add a new layer to active map"))
840 _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
841 helptext = _("Remove selected layer(s)"),
842 sensitive = _can_remove_layer)
843
844 # Layer menu
845 _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
846 sensitive = _has_selected_layer)
847 _method_command("layer_raise", _("&Raise"), "RaiseLayer",
848 helptext = _("Raise selected layer(s)"),
849 sensitive = _has_selected_layer)
850 _method_command("layer_lower", _("&Lower"), "LowerLayer",
851 helptext = _("Lower selected layer(s)"),
852 sensitive = _has_selected_layer)
853 _method_command("layer_show", _("&Show"), "ShowLayer",
854 helptext = _("Make selected layer(s) visible"),
855 sensitive = _has_selected_layer)
856 _method_command("layer_hide", _("&Hide"), "HideLayer",
857 helptext = _("Make selected layer(s) unvisible"),
858 sensitive = _has_selected_layer)
859 _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
860 helptext = _("Show the selected layer's table"),
861 sensitive = _has_selected_layer)
862 _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
863 sensitive = _has_selected_layer)
864 _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
865 sensitive = _has_selected_layer)
866 _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
867 sensitive = _has_selected_layer)
868
869 # Table menu
870 _method_command("table_open", _("&Open..."), "TableOpen")
871 _method_command("table_close", _("&Close"), "TableClose")
872 _method_command("table_show", _("&Show"), "TableShow")
873 _method_command("table_hide", _("&Hide"), "TableHide")
874 _method_command("table_join", _("&Join..."), "TableJoin")
875
876 # Export only under Windows ...
877 map_menu = ["layer_add", "layer_remove", "map_rename",
878 None,
879 "map_projection",
880 None,
881 "map_zoom_in_tool", "map_zoom_out_tool",
882 "map_pan_tool",
883 "map_full_extent",
884 "layer_full_extent",
885 "selected_full_extent",
886 None,
887 "map_identify_tool", "map_label_tool",
888 None,
889 "toggle_legend",
890 None]
891 if wxPlatform == '__WXMSW__':
892 map_menu.append("map_export")
893 map_menu.append("map_print")
894
895 # the menu structure
896 main_menu = Menu("<main>", "<main>",
897 [Menu("file", _("&File"),
898 ["new_session", "open_session", None,
899 "save_session", "save_session_as", None,
900 "toggle_session_tree", None,
901 "exit"]),
902 Menu("map", _("&Map"), map_menu),
903 Menu("layer", _("&Layer"),
904 ["layer_raise", "layer_lower",
905 None,
906 "layer_show", "layer_hide",
907 None,
908 "layer_projection",
909 None,
910 "layer_show_table",
911 "layer_jointable",
912 "layer_unjointable",
913 None,
914 "layer_properties"]),
915 Menu("table", _("&Table"),
916 ["table_open", "table_close",
917 None,
918 "table_show", "table_hide",
919 None,
920 "table_join"]),
921 Menu("help", _("&Help"),
922 ["help_about"])])
923
924 # the main toolbar
925
926 main_toolbar = Menu("<toolbar>", "<toolbar>",
927 ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
928 "map_full_extent",
929 "layer_full_extent",
930 "selected_full_extent",
931 None,
932 "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