/[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 102 - (show annotations)
Fri Apr 19 14:22:25 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: 19733 byte(s)
launch save as dialog for saving new sessions

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"]:
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)
425 else:
426 proj4Dlg = proj4dialog.Proj4Dialog(NULL, map.projection.params)
427 if proj4Dlg.ShowModal() == wxID_OK:
428 params = proj4Dlg.GetParams()
429 if params is not None:
430 proj = Projection(params)
431 else:
432 proj = None
433 map.SetProjection(proj)
434 proj4Dlg.Destroy()
435
436 def ZoomInTool(self):
437 self.canvas.ZoomInTool()
438
439 def ZoomOutTool(self):
440 self.canvas.ZoomOutTool()
441
442 def PanTool(self):
443 self.canvas.PanTool()
444
445 def IdentifyTool(self):
446 self.canvas.IdentifyTool()
447 self.identify_view_on_demand(None, None)
448
449 def LabelTool(self):
450 self.canvas.LabelTool()
451
452 def FullExtent(self):
453 self.canvas.FitMapToWindow()
454
455 def PrintMap(self):
456 self.canvas.Print()
457
458 def identify_view_on_demand(self, layer, shape):
459 name = "identify_view"
460 if self.canvas.CurrentTool() == "IdentifyTool":
461 if not self.dialog_open(name):
462 dialog = identifyview.IdentifyView(self, self.interactor, name)
463 self.add_dialog(name, dialog)
464 dialog.Show(true)
465 else:
466 # FIXME: bring dialog to front?
467 pass
468
469 #
470 # Define all the commands available in the main window
471 #
472
473
474 # Helper functions to define common command implementations
475 def call_method(context, methodname, *args):
476 """Call the context's method methodname with args *args"""
477 apply(getattr(context, methodname), args)
478
479 def _method_command(name, title, method, helptext = "", sensitive = None):
480 """Add a command implemented by a method of the context object"""
481 registry.Add(Command(name, title, call_method, args=(method,),
482 helptext = helptext, sensitive = sensitive))
483 def _tool_command(name, title, method, toolname, helptext = "",
484 icon = ""):
485 """Add a tool command"""
486 def check_current_tool(context, name=toolname):
487 return context.canvas.CurrentTool() == name
488 registry.Add(Command(name, title, call_method, args=(method,),
489 helptext = helptext, icon = icon,
490 checked = check_current_tool))
491
492 def _has_selected_layer(context):
493 """Return true if a layer is selected in the context"""
494 return context.has_selected_layer()
495
496 # File menu
497 _method_command("new_session", "&New Session", "NewSession")
498 _method_command("open_session", "&Open Session", "OpenSession")
499 _method_command("save_session", "&Save Session", "SaveSession")
500 _method_command("save_session_as", "Save Session &As", "SaveSessionAs")
501 _method_command("exit", "&Exit", "Exit")
502
503 # Help menu
504 _method_command("help_about", "&About", "About")
505
506
507 # Map menu
508 _method_command("map_projection", "Pro&jection", "Projection")
509
510 _tool_command("map_zoom_in_tool", "&Zoom in", "ZoomInTool", "ZoomInTool",
511 helptext = "Switch to map-mode 'zoom-in'", icon = "zoom_in")
512 _tool_command("map_zoom_out_tool", "Zoom &out", "ZoomOutTool", "ZoomOutTool",
513 helptext = "Switch to map-mode 'zoom-out'", icon = "zoom_out")
514 _tool_command("map_pan_tool", "&Pan", "PanTool", "PanTool",
515 helptext = "Switch to map-mode 'pan'", icon = "pan")
516 _tool_command("map_identify_tool", "&Identify", "IdentifyTool", "IdentifyTool",
517 helptext = "Switch to map-mode 'identify'", icon = "identify")
518 _tool_command("map_label_tool", "&Label", "LabelTool", "LabelTool",
519 helptext = "Add/Remove labels", icon = "label")
520 _method_command("map_full_extent", "&Full extent", "FullExtent")
521 _method_command("map_print", "Prin&t", "PrintMap", helptext = "Print the map")
522
523 # Layer menu
524 _method_command("layer_add", "&Add Layer", "AddLayer",
525 helptext = "Add a new layer to active map")
526 _method_command("layer_remove", "&Remove Layer", "RemoveLayer",
527 helptext = "Remove selected layer(s)",
528 sensitive = _has_selected_layer)
529 _method_command("layer_fill_color", "&Fill Color", "LayerFillColor",
530 helptext = "Set the fill color of selected layer(s)",
531 sensitive = _has_selected_layer)
532 _method_command("layer_transparent_fill", "&Transparent Fill",
533 "LayerTransparentFill",
534 helptext = "Do not fill the selected layer(s)",
535 sensitive = _has_selected_layer)
536 _method_command("layer_ourline_color", "&Outline Color", "LayerOutlineColor",
537 helptext = "Set the outline color of selected layer(s)",
538 sensitive = _has_selected_layer)
539 _method_command("layer_no_outline", "&No Outline", "LayerNoOutline",
540 helptext = "Do not draw the outline of the selected layer(s)",
541 sensitive = _has_selected_layer)
542 _method_command("layer_raise", "&Raise", "RaiseLayer",
543 helptext = "Raise selected layer(s)",
544 sensitive = _has_selected_layer)
545 _method_command("layer_lower", "&Lower", "LowerLayer",
546 helptext = "Lower selected layer(s)",
547 sensitive = _has_selected_layer)
548 _method_command("layer_show", "&Show", "ShowLayer",
549 helptext = "Make selected layer(s) visible",
550 sensitive = _has_selected_layer)
551 _method_command("layer_hide", "&Hide", "HideLayer",
552 helptext = "Make selected layer(s) unvisible",
553 sensitive = _has_selected_layer)
554 _method_command("layer_show_table", "Show Ta&ble", "LayerShowTable",
555 helptext = "Show the selected layer's table",
556 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