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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 307 - (hide annotations)
Fri Sep 6 10:01:16 2002 UTC (22 years, 6 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 24164 byte(s)
(MainWindow.OnClose): Unsubscribe VIEW_POSITION

1 bh 123 # Copyright (C) 2001, 2002 by Intevation GmbH
2 bh 6 # Authors:
3     # Jan-Oliver Wagner <[email protected]>
4     # Bernhard Herzog <[email protected]>
5     #
6     # This program is free software under the GPL (>=v2)
7     # Read the file COPYING coming with Thuban for details.
8    
9     """
10     The main window
11     """
12    
13     __version__ = "$Revision$"
14    
15 bh 188 import os
16 bh 6
17     from wxPython.wx import *
18    
19     import Thuban
20 bh 188 from Thuban.Model.session import create_empty_session
21 bh 6 from Thuban.Model.layer import Layer
22     from Thuban.Model.color import Color
23     from Thuban.Model.proj import Projection
24    
25     import view
26     import tree
27     import proj4dialog
28     import tableview, identifyview
29 bh 188 from menu import Menu
30 bh 6
31 bh 222 from context import Context
32 bh 6 from command import registry, Command
33 bh 123 from messages import SELECTED_SHAPE, VIEW_POSITION
34 bh 6
35    
36     # the directory where the toolbar icons are stored
37     bitmapdir = os.path.join(Thuban.__path__[0], os.pardir, "Resources", "Bitmaps")
38     bitmapext = ".xpm"
39    
40    
41     class MainWindow(wxFrame):
42    
43 bh 235 def __init__(self, parent, ID, title, application, interactor,
44 bh 238 initial_message = None, size = wxSize(-1, -1)):
45     wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
46 bh 6
47 bh 227 self.application = application
48 bh 37 self.interactor = interactor
49    
50 bh 6 self.CreateStatusBar()
51 bh 235 if initial_message:
52     self.SetStatusText(initial_message)
53 bh 6
54     self.identify_view = None
55    
56     self.init_ids()
57    
58 bh 191 # creat the menubar from the main_menu description
59 bh 188 self.SetMenuBar(self.build_menu_bar(main_menu))
60 bh 6
61 bh 191 # Similarly, create the toolbar from main_toolbar
62     toolbar = self.build_toolbar(main_toolbar)
63 bh 13 # call Realize to make sure that the tools appear.
64     toolbar.Realize()
65 bh 6
66     # Create the map canvas
67 bh 24 canvas = view.MapCanvas(self, -1, interactor)
68 bh 123 canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
69 bh 6 self.canvas = canvas
70    
71 bh 31 self.init_dialogs()
72    
73     interactor.Subscribe(SELECTED_SHAPE, self.identify_view_on_demand)
74    
75 bh 6 EVT_CLOSE(self, self.OnClose)
76    
77     def init_ids(self):
78     """Initialize the ids"""
79     self.current_id = 6000
80     self.id_to_name = {}
81     self.name_to_id = {}
82 bh 193 self.events_bound = {}
83 bh 6
84     def get_id(self, name):
85     """Return the wxWindows id for the command named name.
86    
87     Create a new one if there isn't one yet"""
88     ID = self.name_to_id.get(name)
89     if ID is None:
90     ID = self.current_id
91     self.current_id = self.current_id + 1
92     self.name_to_id[name] = ID
93     self.id_to_name[ID] = name
94     return ID
95 bh 188
96 bh 193 def bind_command_events(self, command, ID):
97     """Bind the necessary events for the given command and ID"""
98     if not self.events_bound.has_key(ID):
99     # the events haven't been bound yet
100     EVT_MENU(self, ID, self.invoke_command)
101     if command.IsDynamic():
102     EVT_UPDATE_UI(self, ID, self.update_command_ui)
103    
104 bh 188 def build_menu_bar(self, menudesc):
105     """Build and return the menu bar from the menu description"""
106     menu_bar = wxMenuBar()
107    
108     for item in menudesc.items:
109     # here the items must all be Menu instances themselves
110     menu_bar.Append(self.build_menu(item), item.title)
111    
112     return menu_bar
113    
114     def build_menu(self, menudesc):
115     """Build and return a wxMenu from a menudescription"""
116     wxmenu = wxMenu()
117     last = None
118     for item in menudesc.items:
119     # here the items must all be Menu instances themselves
120     if item is None:
121     # a separator. Only add one if the last item was not a
122     # separator
123     if last is not None:
124     wxmenu.AppendSeparator()
125     elif isinstance(item, Menu):
126     # a submenu
127     wxmenu.AppendMenu(wxNewId(), item.title, self.build_menu(item))
128     else:
129     # must the name the name of a command
130     self.add_menu_command(wxmenu, item)
131     last = item
132     return wxmenu
133    
134 bh 191 def build_toolbar(self, toolbardesc):
135     """Build and return the main toolbar window from a toolbar description
136    
137     The parameter should be an instance of the Menu class but it
138     should not contain submenus.
139     """
140     toolbar = self.CreateToolBar(wxTB_3DBUTTONS)
141    
142     # set the size of the tools' bitmaps. Not needed on wxGTK, but
143     # on Windows, although it doesn't work very well there. It seems
144     # that only 16x16 icons are really supported on windows.
145     # We probably shouldn't hardwire the bitmap size here.
146     toolbar.SetToolBitmapSize(wxSize(24, 24))
147    
148     for item in toolbardesc.items:
149     if item is None:
150     toolbar.AddSeparator()
151     else:
152     # assume it's a string.
153     self.add_toolbar_command(toolbar, item)
154    
155     return toolbar
156    
157 bh 6 def add_menu_command(self, menu, name):
158     """Add the command with name name to the menu menu.
159    
160     If name is None, add a separator.
161     """
162     if name is None:
163     menu.AppendSeparator()
164     else:
165     command = registry.Command(name)
166     if command is not None:
167     ID = self.get_id(name)
168     menu.Append(ID, command.Title(), command.HelpText(),
169     command.IsCheckCommand())
170 bh 193 self.bind_command_events(command, ID)
171 bh 6 else:
172     print "Unknown command %s" % name
173    
174     def add_toolbar_command(self, toolbar, name):
175     """Add the command with name name to the toolbar toolbar.
176    
177     If name is None, add a separator.
178     """
179     # Assume that all toolbar commands are also menu commmands so
180     # that we don't have to add the event handlers here
181     if name is None:
182     toolbar.AddSeparator()
183     else:
184     command = registry.Command(name)
185     if command is not None:
186     ID = self.get_id(name)
187     filename = os.path.join(bitmapdir, command.Icon()) + bitmapext
188     bitmap = wxBitmap(filename, wxBITMAP_TYPE_XPM)
189     toolbar.AddTool(ID, bitmap,
190     shortHelpString = command.HelpText(),
191     isToggle = command.IsCheckCommand())
192 bh 193 self.bind_command_events(command, ID)
193 bh 6 else:
194     print "Unknown command %s" % name
195    
196 bh 281 def Context(self):
197     """Return the context object for a command invoked from this window
198     """
199     return Context(self.application, self.application.Session(), self)
200    
201 bh 6 def invoke_command(self, event):
202     name = self.id_to_name.get(event.GetId())
203     if name is not None:
204     command = registry.Command(name)
205 bh 281 command.Execute(self.Context())
206 bh 6 else:
207     print "Unknown command ID %d" % event.GetId()
208    
209     def update_command_ui(self, event):
210     #print "update_command_ui", self.id_to_name[event.GetId()]
211 bh 281 context = self.Context()
212 bh 6 command = registry.Command(self.id_to_name[event.GetId()])
213     if command is not None:
214 bh 222 event.Enable(command.Sensitive(context))
215     event.SetText(command.DynText(context))
216 bh 13 if command.IsCheckCommand():
217 bh 222 event.Check(command.Checked(context))
218 bh 6
219 bh 20 def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
220 bh 181 """Run a modal message box with the given text, title and flags
221 bh 20 and return the result"""
222     dlg = wxMessageDialog(self, text, title, flags)
223     result = dlg.ShowModal()
224     dlg.Destroy()
225     return result
226    
227 bh 31 def init_dialogs(self):
228     """Initialize the dialog handling"""
229     # The mainwindow maintains a dict mapping names to open
230     # non-modal dialogs. The dialogs are put into this dict when
231     # they're created and removed when they're closed
232     self.dialogs = {}
233    
234     def add_dialog(self, name, dialog):
235     if self.dialogs.has_key(name):
236     raise RuntimeError("The Dialog named %s is already open" % name)
237     self.dialogs[name] = dialog
238    
239     def dialog_open(self, name):
240     return self.dialogs.has_key(name)
241    
242     def remove_dialog(self, name):
243     del self.dialogs[name]
244    
245     def get_open_dialog(self, name):
246     return self.dialogs.get(name)
247    
248 bh 123 def view_position_changed(self):
249     pos = self.canvas.CurrentPosition()
250     if pos is not None:
251     text = "(%10.10g, %10.10g)" % pos
252     else:
253     text = ""
254     self.SetStatusText(text)
255    
256 bh 58 def save_modified_session(self, can_veto = 1):
257     """If the current session has been modified, ask the user
258     whether to save it and do so if requested. Return the outcome of
259     the dialog (either wxID_OK, wxID_CANCEL or wxID_NO). If the
260     dialog wasn't run return wxID_NO.
261    
262     If the can_veto parameter is true (default) the dialog includes
263     a cancel button, otherwise not.
264     """
265 bh 227 if self.application.session.WasModified():
266 bh 58 flags = wxYES_NO | wxICON_QUESTION
267     if can_veto:
268     flags = flags | wxCANCEL
269     result = self.RunMessageBox("Exit",
270     ("The session has been modified."
271     " Do you want to save it?"),
272     flags)
273     if result == wxID_YES:
274     self.SaveSession()
275     else:
276     result = wxID_NO
277     return result
278    
279 bh 6 def NewSession(self):
280 bh 58 self.save_modified_session()
281 bh 227 self.application.SetSession(create_empty_session())
282 bh 6
283     def OpenSession(self):
284 bh 58 self.save_modified_session()
285 bh 6 dlg = wxFileDialog(self, "Select a session file", ".", "",
286 bh 130 "*.thuban", wxOPEN)
287 bh 6 if dlg.ShowModal() == wxID_OK:
288 bh 227 self.application.OpenSession(dlg.GetPath())
289 bh 6 dlg.Destroy()
290    
291     def SaveSession(self):
292 bh 227 if self.application.session.filename == None:
293 jan 102 self.SaveSessionAs()
294 bh 227 self.application.SaveSession()
295 bh 6
296     def SaveSessionAs(self):
297     dlg = wxFileDialog(self, "Enter a filename for session", ".", "",
298 bh 130 "*.thuban", wxOPEN)
299 bh 6 if dlg.ShowModal() == wxID_OK:
300 bh 227 self.application.session.SetFilename(dlg.GetPath())
301     self.application.SaveSession()
302 bh 6 dlg.Destroy()
303    
304     def Exit(self):
305     self.Close(false)
306    
307     def OnClose(self, event):
308 bh 58 result = self.save_modified_session(can_veto = event.CanVeto())
309     if result == wxID_CANCEL:
310 bh 6 event.Veto()
311     else:
312 bh 307 # FIXME: it would be better to tie the unsubscription to
313     # wx's destroy event, but that isn't implemented for wxGTK
314     # yet.
315     self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
316 bh 6 self.Destroy()
317    
318     def SetMap(self, map):
319     self.canvas.SetMap(map)
320    
321 bh 37 def ShowSessionTree(self):
322     name = "session_tree"
323     dialog = self.get_open_dialog(name)
324     if dialog is None:
325 bh 227 dialog = tree.SessionTreeView(self, self.application, name)
326 bh 37 self.add_dialog(name, dialog)
327     dialog.Show(true)
328     else:
329     # FIXME: bring dialog to front here
330     pass
331    
332 bh 6 def About(self):
333 bh 20 self.RunMessageBox("About",
334     ("Thuban is a program for\n"
335     "exploring geographic data.\n"
336     "Copyright (C) 2001 Intevation GmbH.\n"
337     "Thuban is licensed under the GPL"),
338     wxOK | wxICON_INFORMATION)
339 bh 6
340     def AddLayer(self):
341 frank 119 dlg = wxFileDialog(self, "Select a data file", ".", "", "*.*",
342 bh 6 wxOPEN)
343     if dlg.ShowModal() == wxID_OK:
344     filename = dlg.GetPath()
345     title = os.path.splitext(os.path.basename(filename))[0]
346     layer = Layer(title, filename)
347 bh 18 map = self.canvas.Map()
348     has_layers = map.HasLayers()
349 bh 20 try:
350     map.AddLayer(layer)
351     except IOError:
352     # the layer couldn't be opened
353     self.RunMessageBox("Add Layer",
354     "Can't open the file '%s'." % filename)
355     else:
356     if not has_layers:
357     # if we're adding a layer to an empty map, for the
358     # new map to the window
359     self.canvas.FitMapToWindow()
360 bh 6 dlg.Destroy()
361    
362     def RemoveLayer(self):
363     layer = self.current_layer()
364     if layer is not None:
365     self.canvas.Map().RemoveLayer(layer)
366    
367 bh 299 def CanRemoveLayer(self):
368     """Return true if the currently selected layer can be deleted.
369    
370     If no layer is selected return false.
371    
372     The return value of this method determines whether the remove
373     layer command is sensitive in menu.
374     """
375     layer = self.current_layer()
376     if layer is not None:
377     return self.canvas.Map().CanRemoveLayer(layer)
378     return 0
379    
380 bh 6 def RaiseLayer(self):
381     layer = self.current_layer()
382     if layer is not None:
383     self.canvas.Map().RaiseLayer(layer)
384 bh 222
385 bh 6 def LowerLayer(self):
386     layer = self.current_layer()
387     if layer is not None:
388     self.canvas.Map().LowerLayer(layer)
389    
390     def current_layer(self):
391     """Return the currently selected layer.
392    
393     If no layer is selected, return None
394     """
395 bh 37 return self.interactor.SelectedLayer()
396 bh 6
397     def has_selected_layer(self):
398     """Return true if a layer is currently selected"""
399 bh 37 return self.interactor.HasSelectedLayer()
400 bh 6
401     def choose_color(self):
402     """Run the color selection dialog and return the selected color.
403    
404     If the user cancels, return None.
405     """
406     dlg = wxColourDialog(self)
407     color = None
408     if dlg.ShowModal() == wxID_OK:
409     data = dlg.GetColourData()
410     wxc = data.GetColour()
411     color = Color(wxc.Red() / 255.0,
412     wxc.Green() / 255.0,
413     wxc.Blue() / 255.0)
414     dlg.Destroy()
415     return color
416    
417     def LayerFillColor(self):
418     layer = self.current_layer()
419     if layer is not None:
420     color = self.choose_color()
421     if color is not None:
422     layer.SetFill(color)
423    
424     def LayerTransparentFill(self):
425     layer = self.current_layer()
426     if layer is not None:
427     layer.SetFill(None)
428    
429     def LayerOutlineColor(self):
430     layer = self.current_layer()
431     if layer is not None:
432     color = self.choose_color()
433     if color is not None:
434     layer.SetStroke(color)
435    
436     def LayerNoOutline(self):
437     layer = self.current_layer()
438     if layer is not None:
439     layer.SetStroke(None)
440    
441     def HideLayer(self):
442     layer = self.current_layer()
443     if layer is not None:
444     layer.SetVisible(0)
445    
446     def ShowLayer(self):
447     layer = self.current_layer()
448     if layer is not None:
449     layer.SetVisible(1)
450    
451     def LayerShowTable(self):
452     layer = self.current_layer()
453     if layer is not None:
454 bh 31 table = layer.table
455     name = "table_view" + str(id(table))
456     dialog = self.get_open_dialog(name)
457     if dialog is None:
458 bh 278 dialog = tableview.LayerTableFrame(self, self.interactor, name,
459     "Table: %s" % layer.Title(),
460     layer, table)
461 bh 31 self.add_dialog(name, dialog)
462     dialog.Show(true)
463     else:
464     # FIXME: bring dialog to front here
465     pass
466 bh 6
467     def Projection(self):
468     map = self.canvas.Map()
469     proj = map.projection
470     if proj is None:
471 jan 110 proj4Dlg = proj4dialog.Proj4Dialog(NULL, None, map.BoundingBox())
472 bh 6 else:
473 jan 110 proj4Dlg = proj4dialog.Proj4Dialog(NULL, map.projection.params,
474     map.BoundingBox())
475 bh 6 if proj4Dlg.ShowModal() == wxID_OK:
476     params = proj4Dlg.GetParams()
477     if params is not None:
478     proj = Projection(params)
479     else:
480     proj = None
481     map.SetProjection(proj)
482     proj4Dlg.Destroy()
483    
484     def ZoomInTool(self):
485     self.canvas.ZoomInTool()
486    
487     def ZoomOutTool(self):
488     self.canvas.ZoomOutTool()
489    
490     def PanTool(self):
491     self.canvas.PanTool()
492    
493     def IdentifyTool(self):
494     self.canvas.IdentifyTool()
495 bh 49 self.identify_view_on_demand(None, None)
496 bh 6
497     def LabelTool(self):
498     self.canvas.LabelTool()
499    
500     def FullExtent(self):
501     self.canvas.FitMapToWindow()
502    
503     def PrintMap(self):
504     self.canvas.Print()
505    
506 bh 31 def identify_view_on_demand(self, layer, shape):
507     name = "identify_view"
508     if self.canvas.CurrentTool() == "IdentifyTool":
509     if not self.dialog_open(name):
510 bh 37 dialog = identifyview.IdentifyView(self, self.interactor, name)
511 bh 31 self.add_dialog(name, dialog)
512     dialog.Show(true)
513     else:
514 bh 33 # FIXME: bring dialog to front?
515 bh 31 pass
516 bh 6
517     #
518     # Define all the commands available in the main window
519     #
520    
521    
522     # Helper functions to define common command implementations
523     def call_method(context, methodname, *args):
524 bh 222 """Call the mainwindow's method methodname with args *args"""
525     apply(getattr(context.mainwindow, methodname), args)
526 bh 6
527 jan 110 def _method_command(name, title, method, helptext = "",
528     icon = "", sensitive = None):
529 bh 222 """Add a command implemented by a method of the mainwindow object"""
530 bh 6 registry.Add(Command(name, title, call_method, args=(method,),
531 jan 110 helptext = helptext, icon = icon,
532     sensitive = sensitive))
533    
534 bh 270 def make_check_current_tool(toolname):
535     """Return a function that tests if the currently active tool is toolname
536    
537     The returned function can be called with the context and returns
538     true iff the currently active tool's name is toolname. It's directly
539     usable as the 'checked' callback of a command.
540     """
541     def check_current_tool(context, name=toolname):
542     return context.mainwindow.canvas.CurrentTool() == name
543     return check_current_tool
544    
545 bh 6 def _tool_command(name, title, method, toolname, helptext = "",
546     icon = ""):
547     """Add a tool command"""
548     registry.Add(Command(name, title, call_method, args=(method,),
549     helptext = helptext, icon = icon,
550 bh 270 checked = make_check_current_tool(toolname)))
551 bh 6
552     def _has_selected_layer(context):
553     """Return true if a layer is selected in the context"""
554 bh 222 return context.mainwindow.has_selected_layer()
555 bh 6
556 bh 299 def _can_remove_layer(context):
557     return context.mainwindow.CanRemoveLayer()
558    
559 jan 264 def _has_tree_window_shown(context):
560     """Return true if the tree window is shown"""
561     return context.mainwindow.get_open_dialog("session_tree") is None
562    
563 bh 6 # File menu
564     _method_command("new_session", "&New Session", "NewSession")
565     _method_command("open_session", "&Open Session", "OpenSession")
566     _method_command("save_session", "&Save Session", "SaveSession")
567     _method_command("save_session_as", "Save Session &As", "SaveSessionAs")
568 jan 264 _method_command("show_session_tree", "Show Session &Tree", "ShowSessionTree",
569     sensitive = _has_tree_window_shown)
570 bh 6 _method_command("exit", "&Exit", "Exit")
571    
572     # Help menu
573     _method_command("help_about", "&About", "About")
574    
575    
576     # Map menu
577     _method_command("map_projection", "Pro&jection", "Projection")
578    
579     _tool_command("map_zoom_in_tool", "&Zoom in", "ZoomInTool", "ZoomInTool",
580     helptext = "Switch to map-mode 'zoom-in'", icon = "zoom_in")
581     _tool_command("map_zoom_out_tool", "Zoom &out", "ZoomOutTool", "ZoomOutTool",
582     helptext = "Switch to map-mode 'zoom-out'", icon = "zoom_out")
583     _tool_command("map_pan_tool", "&Pan", "PanTool", "PanTool",
584     helptext = "Switch to map-mode 'pan'", icon = "pan")
585     _tool_command("map_identify_tool", "&Identify", "IdentifyTool", "IdentifyTool",
586     helptext = "Switch to map-mode 'identify'", icon = "identify")
587     _tool_command("map_label_tool", "&Label", "LabelTool", "LabelTool",
588     helptext = "Add/Remove labels", icon = "label")
589 jan 110 _method_command("map_full_extent", "&Full extent", "FullExtent",
590     helptext = "Full Extent", icon = "fullextent")
591 bh 6 _method_command("map_print", "Prin&t", "PrintMap", helptext = "Print the map")
592    
593     # Layer menu
594 bh 84 _method_command("layer_add", "&Add Layer", "AddLayer",
595 bh 6 helptext = "Add a new layer to active map")
596 bh 84 _method_command("layer_remove", "&Remove Layer", "RemoveLayer",
597 bh 6 helptext = "Remove selected layer(s)",
598 bh 299 sensitive = _can_remove_layer)
599 bh 6 _method_command("layer_fill_color", "&Fill Color", "LayerFillColor",
600     helptext = "Set the fill color of selected layer(s)",
601     sensitive = _has_selected_layer)
602     _method_command("layer_transparent_fill", "&Transparent Fill",
603     "LayerTransparentFill",
604     helptext = "Do not fill the selected layer(s)",
605     sensitive = _has_selected_layer)
606 bh 185 _method_command("layer_outline_color", "&Outline Color", "LayerOutlineColor",
607 bh 6 helptext = "Set the outline color of selected layer(s)",
608     sensitive = _has_selected_layer)
609     _method_command("layer_no_outline", "&No Outline", "LayerNoOutline",
610     helptext = "Do not draw the outline of the selected layer(s)",
611     sensitive = _has_selected_layer)
612     _method_command("layer_raise", "&Raise", "RaiseLayer",
613     helptext = "Raise selected layer(s)",
614     sensitive = _has_selected_layer)
615     _method_command("layer_lower", "&Lower", "LowerLayer",
616     helptext = "Lower selected layer(s)",
617     sensitive = _has_selected_layer)
618     _method_command("layer_show", "&Show", "ShowLayer",
619     helptext = "Make selected layer(s) visible",
620     sensitive = _has_selected_layer)
621     _method_command("layer_hide", "&Hide", "HideLayer",
622     helptext = "Make selected layer(s) unvisible",
623     sensitive = _has_selected_layer)
624     _method_command("layer_show_table", "Show Ta&ble", "LayerShowTable",
625     helptext = "Show the selected layer's table",
626     sensitive = _has_selected_layer)
627 bh 188
628    
629     # the menu structure
630     main_menu = Menu("<main>", "<main>",
631     [Menu("file", "&File",
632     ["new_session", "open_session", None,
633     "save_session", "save_session_as", None,
634     "show_session_tree", None,
635     "exit"]),
636     Menu("map", "&Map",
637     ["layer_add", "layer_remove",
638     None,
639     "map_projection",
640     None,
641     "map_zoom_in_tool", "map_zoom_out_tool",
642     "map_pan_tool", "map_identify_tool", "map_label_tool",
643     None,
644     "map_full_extent",
645     None,
646     "map_print"]),
647     Menu("layer", "&Layer",
648     ["layer_fill_color", "layer_transparent_fill",
649     "layer_outline_color", "layer_no_outline",
650     None,
651     "layer_raise", "layer_lower",
652     None,
653     "layer_show", "layer_hide",
654     None,
655     "layer_show_table"]),
656     Menu("help", "&Help",
657     ["help_about"])])
658 bh 191
659     # the main toolbar
660    
661     main_toolbar = Menu("<toolbar>", "<toolbar>",
662     ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
663     "map_identify_tool", "map_label_tool", "map_full_extent"])

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26