/[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 58 - (hide annotations)
Thu Sep 13 13:56:23 2001 UTC (23 years, 5 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 19642 byte(s)
	* Thuban/UI/mainwindow.py (MainWindow.NewSession): Use
	create_empty_session session to create the new, empty session.

	* Thuban/UI/mainwindow.py (MainWindow.__init__): Set the size of
	the tool bitmaps.
	(MainWindow.OnClose, MainWindow.save_modified_session): Separate
	the code that asks whether the session should be saved into the
	new method save_modified_session.
	(MainWindow.OpenSession, MainWindow.NewSession): Use the new
	method to save modified session here too.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26