/[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 191 - (hide annotations)
Tue May 28 16:04:49 2002 UTC (22 years, 9 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 22129 byte(s)
	* Thuban/UI/mainwindow.py (MainWindow.__init__, main_toolbar):
	Move the toolbar definition to the Menu instance main_toolbar.
	(MainWindow.build_toolbar): New method to build the toolbar
	similar to the build_menu methods

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