/[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 110 - (show annotations)
Sun Apr 21 17:28:16 2002 UTC (22 years, 10 months ago) by jan
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 20109 byte(s)
added full-extent to toolbar; adapted proj4 call

1 # 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 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
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 self.canvas = canvas
115
116 self.init_dialogs()
117
118 interactor.Subscribe(SELECTED_SHAPE, self.identify_view_on_demand)
119
120 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 if command.IsCheckCommand():
195 event.Check(command.Checked(self))
196
197 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 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 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 def NewSession(self):
250 self.save_modified_session()
251 main.app.SetSession(create_empty_session())
252
253 def OpenSession(self):
254 self.save_modified_session()
255 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 if main.app.session.filename == None:
263 self.SaveSessionAs()
264 main.app.SaveSession()
265
266 def SaveSessionAs(self):
267 dlg = wxFileDialog(self, "Enter a filename for session", ".", "",
268 "*.session", wxOPEN)
269 if dlg.ShowModal() == wxID_OK:
270 main.app.session.SetFilename(dlg.GetPath())
271 main.app.SaveSession()
272 dlg.Destroy()
273
274 def Exit(self):
275 self.Close(false)
276
277 def OnClose(self, event):
278 result = self.save_modified_session(can_veto = event.CanVeto())
279 if result == wxID_CANCEL:
280 event.Veto()
281 else:
282 self.Destroy()
283
284 def SetMap(self, map):
285 self.canvas.SetMap(map)
286
287 def ShowSessionTree(self):
288 name = "session_tree"
289 dialog = self.get_open_dialog(name)
290 if dialog is None:
291 dialog = tree.SessionTreeView(self, main.app, name)
292 self.add_dialog(name, dialog)
293 dialog.Show(true)
294 else:
295 # FIXME: bring dialog to front here
296 pass
297
298 def About(self):
299 self.RunMessageBox("About",
300 ("Thuban is a program for\n"
301 "exploring geographic data.\n"
302 "Copyright (C) 2001 Intevation GmbH.\n"
303 "Thuban is licensed under the GPL"),
304 wxOK | wxICON_INFORMATION)
305
306 def AddLayer(self):
307 dlg = wxFileDialog(self, "Select a session file", ".", "", "*.*",
308 wxOPEN)
309 if dlg.ShowModal() == wxID_OK:
310 filename = dlg.GetPath()
311 title = os.path.splitext(os.path.basename(filename))[0]
312 layer = Layer(title, filename)
313 map = self.canvas.Map()
314 has_layers = map.HasLayers()
315 try:
316 map.AddLayer(layer)
317 except IOError:
318 # the layer couldn't be opened
319 self.RunMessageBox("Add Layer",
320 "Can't open the file '%s'." % filename)
321 else:
322 if not has_layers:
323 # if we're adding a layer to an empty map, for the
324 # new map to the window
325 self.canvas.FitMapToWindow()
326 dlg.Destroy()
327
328 def RemoveLayer(self):
329 layer = self.current_layer()
330 if layer is not None:
331 self.canvas.Map().RemoveLayer(layer)
332
333 def RaiseLayer(self):
334 layer = self.current_layer()
335 if layer is not None:
336 self.canvas.Map().RaiseLayer(layer)
337
338 def LowerLayer(self):
339 layer = self.current_layer()
340 if layer is not None:
341 self.canvas.Map().LowerLayer(layer)
342
343 def current_layer(self):
344 """Return the currently selected layer.
345
346 If no layer is selected, return None
347 """
348 return self.interactor.SelectedLayer()
349
350 def has_selected_layer(self):
351 """Return true if a layer is currently selected"""
352 return self.interactor.HasSelectedLayer()
353
354 def choose_color(self):
355 """Run the color selection dialog and return the selected color.
356
357 If the user cancels, return None.
358 """
359 dlg = wxColourDialog(self)
360 color = None
361 if dlg.ShowModal() == wxID_OK:
362 data = dlg.GetColourData()
363 wxc = data.GetColour()
364 color = Color(wxc.Red() / 255.0,
365 wxc.Green() / 255.0,
366 wxc.Blue() / 255.0)
367 dlg.Destroy()
368 return color
369
370 def LayerFillColor(self):
371 layer = self.current_layer()
372 if layer is not None:
373 color = self.choose_color()
374 if color is not None:
375 layer.SetFill(color)
376
377 def LayerTransparentFill(self):
378 layer = self.current_layer()
379 if layer is not None:
380 layer.SetFill(None)
381
382 def LayerOutlineColor(self):
383 layer = self.current_layer()
384 if layer is not None:
385 color = self.choose_color()
386 if color is not None:
387 layer.SetStroke(color)
388
389 def LayerNoOutline(self):
390 layer = self.current_layer()
391 if layer is not None:
392 layer.SetStroke(None)
393
394 def HideLayer(self):
395 layer = self.current_layer()
396 if layer is not None:
397 layer.SetVisible(0)
398
399 def ShowLayer(self):
400 layer = self.current_layer()
401 if layer is not None:
402 layer.SetVisible(1)
403
404 def LayerShowTable(self):
405 layer = self.current_layer()
406 if layer is not None:
407 table = layer.table
408 name = "table_view" + str(id(table))
409 dialog = self.get_open_dialog(name)
410 if dialog is None:
411 dialog = tableview.TableFrame(self, self.interactor, name,
412 "Table: %s" % layer.Title(),
413 layer, table)
414 self.add_dialog(name, dialog)
415 dialog.Show(true)
416 else:
417 # FIXME: bring dialog to front here
418 pass
419
420 def Projection(self):
421 map = self.canvas.Map()
422 proj = map.projection
423 if proj is None:
424 proj4Dlg = proj4dialog.Proj4Dialog(NULL, None, map.BoundingBox())
425 else:
426 proj4Dlg = proj4dialog.Proj4Dialog(NULL, map.projection.params,
427 map.BoundingBox())
428 if proj4Dlg.ShowModal() == wxID_OK:
429 params = proj4Dlg.GetParams()
430 if params is not None:
431 proj = Projection(params)
432 else:
433 proj = None
434 map.SetProjection(proj)
435 proj4Dlg.Destroy()
436
437 def ZoomInTool(self):
438 self.canvas.ZoomInTool()
439
440 def ZoomOutTool(self):
441 self.canvas.ZoomOutTool()
442
443 def PanTool(self):
444 self.canvas.PanTool()
445
446 def IdentifyTool(self):
447 self.canvas.IdentifyTool()
448 self.identify_view_on_demand(None, None)
449
450 def LabelTool(self):
451 self.canvas.LabelTool()
452
453 def FullExtent(self):
454 self.canvas.FitMapToWindow()
455
456 def PrintMap(self):
457 self.canvas.Print()
458
459 def identify_view_on_demand(self, layer, shape):
460 name = "identify_view"
461 if self.canvas.CurrentTool() == "IdentifyTool":
462 if not self.dialog_open(name):
463 dialog = identifyview.IdentifyView(self, self.interactor, name)
464 self.add_dialog(name, dialog)
465 dialog.Show(true)
466 else:
467 # FIXME: bring dialog to front?
468 pass
469
470 #
471 # Define all the commands available in the main window
472 #
473
474
475 # Helper functions to define common command implementations
476 def call_method(context, methodname, *args):
477 """Call the context's method methodname with args *args"""
478 apply(getattr(context, methodname), args)
479
480 def _method_command(name, title, method, helptext = "",
481 icon = "", sensitive = None):
482 """Add a command implemented by a method of the context object"""
483 registry.Add(Command(name, title, call_method, args=(method,),
484 helptext = helptext, icon = icon,
485 sensitive = sensitive))
486
487 def _tool_command(name, title, method, toolname, helptext = "",
488 icon = ""):
489 """Add a tool command"""
490 def check_current_tool(context, name=toolname):
491 return context.canvas.CurrentTool() == name
492 registry.Add(Command(name, title, call_method, args=(method,),
493 helptext = helptext, icon = icon,
494 checked = check_current_tool))
495
496 def _has_selected_layer(context):
497 """Return true if a layer is selected in the context"""
498 return context.has_selected_layer()
499
500 # File menu
501 _method_command("new_session", "&New Session", "NewSession")
502 _method_command("open_session", "&Open Session", "OpenSession")
503 _method_command("save_session", "&Save Session", "SaveSession")
504 _method_command("save_session_as", "Save Session &As", "SaveSessionAs")
505 _method_command("exit", "&Exit", "Exit")
506
507 # Help menu
508 _method_command("help_about", "&About", "About")
509
510
511 # Map menu
512 _method_command("map_projection", "Pro&jection", "Projection")
513
514 _tool_command("map_zoom_in_tool", "&Zoom in", "ZoomInTool", "ZoomInTool",
515 helptext = "Switch to map-mode 'zoom-in'", icon = "zoom_in")
516 _tool_command("map_zoom_out_tool", "Zoom &out", "ZoomOutTool", "ZoomOutTool",
517 helptext = "Switch to map-mode 'zoom-out'", icon = "zoom_out")
518 _tool_command("map_pan_tool", "&Pan", "PanTool", "PanTool",
519 helptext = "Switch to map-mode 'pan'", icon = "pan")
520 _tool_command("map_identify_tool", "&Identify", "IdentifyTool", "IdentifyTool",
521 helptext = "Switch to map-mode 'identify'", icon = "identify")
522 _tool_command("map_label_tool", "&Label", "LabelTool", "LabelTool",
523 helptext = "Add/Remove labels", icon = "label")
524 #_tool_command("map_full_extent", "&Full extent", "FullExtent", "FullExtent",
525 # helptext = "Full Extent", icon = "fullextent")
526 _method_command("map_full_extent", "&Full extent", "FullExtent",
527 helptext = "Full Extent", icon = "fullextent")
528 _method_command("map_print", "Prin&t", "PrintMap", helptext = "Print the map")
529
530 # Layer menu
531 _method_command("layer_add", "&Add Layer", "AddLayer",
532 helptext = "Add a new layer to active map")
533 _method_command("layer_remove", "&Remove Layer", "RemoveLayer",
534 helptext = "Remove selected layer(s)",
535 sensitive = _has_selected_layer)
536 _method_command("layer_fill_color", "&Fill Color", "LayerFillColor",
537 helptext = "Set the fill color of selected layer(s)",
538 sensitive = _has_selected_layer)
539 _method_command("layer_transparent_fill", "&Transparent Fill",
540 "LayerTransparentFill",
541 helptext = "Do not fill the selected layer(s)",
542 sensitive = _has_selected_layer)
543 _method_command("layer_ourline_color", "&Outline Color", "LayerOutlineColor",
544 helptext = "Set the outline color of selected layer(s)",
545 sensitive = _has_selected_layer)
546 _method_command("layer_no_outline", "&No Outline", "LayerNoOutline",
547 helptext = "Do not draw the outline of the selected layer(s)",
548 sensitive = _has_selected_layer)
549 _method_command("layer_raise", "&Raise", "RaiseLayer",
550 helptext = "Raise selected layer(s)",
551 sensitive = _has_selected_layer)
552 _method_command("layer_lower", "&Lower", "LowerLayer",
553 helptext = "Lower selected layer(s)",
554 sensitive = _has_selected_layer)
555 _method_command("layer_show", "&Show", "ShowLayer",
556 helptext = "Make selected layer(s) visible",
557 sensitive = _has_selected_layer)
558 _method_command("layer_hide", "&Hide", "HideLayer",
559 helptext = "Make selected layer(s) unvisible",
560 sensitive = _has_selected_layer)
561 _method_command("layer_show_table", "Show Ta&ble", "LayerShowTable",
562 helptext = "Show the selected layer's table",
563 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