/[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 130 - (show annotations)
Fri May 3 14:50:18 2002 UTC (22 years, 10 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 20278 byte(s)
	* Thuban/UI/mainwindow.py (MainWindow.SaveSessionAs,
	MainWindow.OpenSession): Change the file extension of the session
	files to .thuban

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