/[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 181 - (show annotations)
Wed May 22 13:42:04 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: 20404 byte(s)
	* Thuban/UI/mainwindow.py (MainWindow.RunMessageBox): Fix a typo
	in the docstring

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