/[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 563 - (show annotations)
Wed Mar 26 11:07:02 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 32852 byte(s)
Added sash windows to the main window and supporting functions for
manipulating the sashes.
(MainWindow.ShowLegend): Create a DockableWindow with the LegendPanel as the
contents.

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