/[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 1084 - (hide annotations)
Wed May 28 10:25:09 2003 UTC (21 years, 9 months ago) by jan
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 38497 byte(s)
(MainWindow.TableClose, MainWindow.TableShow): sort the selection list
for the dialog.

1 bh 535 # Copyright (C) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Jan-Oliver Wagner <[email protected]>
4     # Bernhard Herzog <[email protected]>
5 frank 911 # Frank Koormann <[email protected]>
6 bh 6 #
7     # This program is free software under the GPL (>=v2)
8     # Read the file COPYING coming with Thuban for details.
9    
10     """
11     The main window
12     """
13    
14     __version__ = "$Revision$"
15    
16 jonathan 517 __ThubanVersion__ = "0.2" #"$THUBAN_0_2$"
17     #__BuildDate__ = "$Date$"
18    
19 bh 188 import os
20 bh 6
21     from wxPython.wx import *
22 frank 923 from wxPython.wx import __version__ as wxPython_version
23 bh 6
24 jan 1014 from wxPython.lib.dialogs import wxMultipleChoiceDialog
25    
26 bh 6 import Thuban
27 frank 923 import Thuban.version
28    
29 jan 374 from Thuban import _
30 bh 188 from Thuban.Model.session import create_empty_session
31 jonathan 937 from Thuban.Model.layer import Layer, RasterLayer
32 bh 6
33     import view
34     import tree
35     import tableview, identifyview
36 jonathan 633 from Thuban.UI.classifier import Classifier
37 jonathan 550 import legend
38 bh 188 from menu import Menu
39 bh 6
40 bh 222 from context import Context
41 bh 357 from command import registry, Command, ToolCommand
42 bh 704 from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION
43 bh 6
44 bh 704 from Thuban.UI.dock import DockFrame
45 jonathan 879 from Thuban.UI.join import JoinDialog
46 bh 6
47 jonathan 653 import resource
48 jonathan 563
49 jonathan 713 import projdialog
50 jonathan 653
51 bh 6
52 jonathan 713
53 jonathan 573 class MainWindow(DockFrame):
54 bh 6
55 bh 535 # Some messages that can be subscribed/unsubscribed directly through
56     # the MapCanvas come in fact from other objects. This is a map to
57     # map those messages to the names of the instance variables they
58     # actually come from. This delegation is implemented in the
59     # Subscribe and unsubscribed methods
60     delegated_messages = {LAYER_SELECTED: "canvas",
61     SHAPES_SELECTED: "canvas"}
62    
63     # Methods delegated to some instance variables. The delegation is
64     # implemented in the __getattr__ method.
65     delegated_methods = {"SelectLayer": "canvas",
66     "SelectShapes": "canvas",
67 bh 1074 "SelectedLayer": "canvas",
68 jonathan 879 "SelectedShapes": "canvas",
69 bh 535 }
70    
71 bh 235 def __init__(self, parent, ID, title, application, interactor,
72 bh 238 initial_message = None, size = wxSize(-1, -1)):
73 jonathan 573 DockFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
74     #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
75 bh 6
76 bh 227 self.application = application
77 bh 37
78 bh 6 self.CreateStatusBar()
79 bh 235 if initial_message:
80     self.SetStatusText(initial_message)
81 bh 6
82     self.identify_view = None
83    
84     self.init_ids()
85    
86 bh 191 # creat the menubar from the main_menu description
87 bh 188 self.SetMenuBar(self.build_menu_bar(main_menu))
88 bh 6
89 bh 191 # Similarly, create the toolbar from main_toolbar
90     toolbar = self.build_toolbar(main_toolbar)
91 bh 13 # call Realize to make sure that the tools appear.
92     toolbar.Realize()
93 bh 6
94 jonathan 563
95 bh 6 # Create the map canvas
96 bh 535 canvas = view.MapCanvas(self, -1)
97 bh 123 canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
98 bh 535 canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
99 bh 6 self.canvas = canvas
100    
101 jonathan 573 self.SetMainWindow(self.canvas)
102    
103 jonathan 563 self.SetAutoLayout(True)
104    
105 bh 31 self.init_dialogs()
106    
107 frank 951 EVT_CLOSE(self, self.OnClose)
108 bh 6
109 bh 535 def Subscribe(self, channel, *args):
110     """Subscribe a function to a message channel.
111    
112     If channel is one of the delegated messages call the appropriate
113     object's Subscribe method. Otherwise do nothing.
114     """
115     if channel in self.delegated_messages:
116     object = getattr(self, self.delegated_messages[channel])
117     object.Subscribe(channel, *args)
118     else:
119     print "Trying to subscribe to unsupported channel %s" % channel
120    
121     def Unsubscribe(self, channel, *args):
122     """Unsubscribe a function from a message channel.
123    
124     If channel is one of the delegated messages call the appropriate
125     object's Unsubscribe method. Otherwise do nothing.
126     """
127     if channel in self.delegated_messages:
128     object = getattr(self, self.delegated_messages[channel])
129     object.Unsubscribe(channel, *args)
130    
131     def __getattr__(self, attr):
132     """If attr is one of the delegated methods return that method
133    
134     Otherwise raise AttributeError.
135     """
136     if attr in self.delegated_methods:
137     return getattr(getattr(self, self.delegated_methods[attr]), attr)
138     raise AttributeError(attr)
139    
140 bh 6 def init_ids(self):
141     """Initialize the ids"""
142     self.current_id = 6000
143     self.id_to_name = {}
144     self.name_to_id = {}
145 bh 193 self.events_bound = {}
146 bh 6
147     def get_id(self, name):
148     """Return the wxWindows id for the command named name.
149    
150     Create a new one if there isn't one yet"""
151     ID = self.name_to_id.get(name)
152     if ID is None:
153     ID = self.current_id
154     self.current_id = self.current_id + 1
155     self.name_to_id[name] = ID
156     self.id_to_name[ID] = name
157     return ID
158 bh 188
159 bh 193 def bind_command_events(self, command, ID):
160     """Bind the necessary events for the given command and ID"""
161     if not self.events_bound.has_key(ID):
162     # the events haven't been bound yet
163     EVT_MENU(self, ID, self.invoke_command)
164     if command.IsDynamic():
165     EVT_UPDATE_UI(self, ID, self.update_command_ui)
166    
167 bh 188 def build_menu_bar(self, menudesc):
168     """Build and return the menu bar from the menu description"""
169     menu_bar = wxMenuBar()
170    
171     for item in menudesc.items:
172     # here the items must all be Menu instances themselves
173     menu_bar.Append(self.build_menu(item), item.title)
174    
175     return menu_bar
176    
177     def build_menu(self, menudesc):
178 bh 314 """Return a wxMenu built from the menu description menudesc"""
179 bh 188 wxmenu = wxMenu()
180     last = None
181     for item in menudesc.items:
182     if item is None:
183     # a separator. Only add one if the last item was not a
184     # separator
185     if last is not None:
186     wxmenu.AppendSeparator()
187     elif isinstance(item, Menu):
188     # a submenu
189     wxmenu.AppendMenu(wxNewId(), item.title, self.build_menu(item))
190     else:
191     # must the name the name of a command
192     self.add_menu_command(wxmenu, item)
193     last = item
194     return wxmenu
195    
196 bh 191 def build_toolbar(self, toolbardesc):
197     """Build and return the main toolbar window from a toolbar description
198    
199     The parameter should be an instance of the Menu class but it
200     should not contain submenus.
201     """
202     toolbar = self.CreateToolBar(wxTB_3DBUTTONS)
203    
204     # set the size of the tools' bitmaps. Not needed on wxGTK, but
205     # on Windows, although it doesn't work very well there. It seems
206     # that only 16x16 icons are really supported on windows.
207     # We probably shouldn't hardwire the bitmap size here.
208     toolbar.SetToolBitmapSize(wxSize(24, 24))
209    
210     for item in toolbardesc.items:
211     if item is None:
212     toolbar.AddSeparator()
213     else:
214     # assume it's a string.
215     self.add_toolbar_command(toolbar, item)
216    
217     return toolbar
218    
219 bh 6 def add_menu_command(self, menu, name):
220     """Add the command with name name to the menu menu.
221    
222     If name is None, add a separator.
223     """
224     if name is None:
225     menu.AppendSeparator()
226     else:
227     command = registry.Command(name)
228     if command is not None:
229     ID = self.get_id(name)
230     menu.Append(ID, command.Title(), command.HelpText(),
231     command.IsCheckCommand())
232 bh 193 self.bind_command_events(command, ID)
233 bh 6 else:
234 jan 374 print _("Unknown command %s") % name
235 bh 6
236     def add_toolbar_command(self, toolbar, name):
237     """Add the command with name name to the toolbar toolbar.
238    
239     If name is None, add a separator.
240     """
241     # Assume that all toolbar commands are also menu commmands so
242     # that we don't have to add the event handlers here
243     if name is None:
244     toolbar.AddSeparator()
245     else:
246     command = registry.Command(name)
247     if command is not None:
248     ID = self.get_id(name)
249 jonathan 653 bitmap = resource.GetBitmapResource(command.Icon(),
250     wxBITMAP_TYPE_XPM)
251 bh 6 toolbar.AddTool(ID, bitmap,
252     shortHelpString = command.HelpText(),
253     isToggle = command.IsCheckCommand())
254 bh 193 self.bind_command_events(command, ID)
255 bh 6 else:
256 jan 374 print _("Unknown command %s") % name
257 bh 6
258 bh 281 def Context(self):
259     """Return the context object for a command invoked from this window
260     """
261     return Context(self.application, self.application.Session(), self)
262    
263 bh 6 def invoke_command(self, event):
264     name = self.id_to_name.get(event.GetId())
265     if name is not None:
266     command = registry.Command(name)
267 bh 281 command.Execute(self.Context())
268 bh 6 else:
269 jan 374 print _("Unknown command ID %d") % event.GetId()
270 bh 6
271     def update_command_ui(self, event):
272     #print "update_command_ui", self.id_to_name[event.GetId()]
273 bh 281 context = self.Context()
274 bh 6 command = registry.Command(self.id_to_name[event.GetId()])
275     if command is not None:
276 bh 357 sensitive = command.Sensitive(context)
277     event.Enable(sensitive)
278     if command.IsTool() and not sensitive and command.Checked(context):
279     # When a checked tool command is disabled deselect all
280     # tools. Otherwise the tool would remain active but it
281     # might lead to errors if the tools stays active. This
282     # problem occurred in GREAT-ER and this fixes it, but
283     # it's not clear to me whether this is really the best
284     # way to do it (BH, 20021206).
285     self.canvas.SelectTool(None)
286 bh 222 event.SetText(command.DynText(context))
287 bh 13 if command.IsCheckCommand():
288 bh 357 event.Check(command.Checked(context))
289 bh 6
290 bh 20 def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
291 bh 181 """Run a modal message box with the given text, title and flags
292 bh 20 and return the result"""
293     dlg = wxMessageDialog(self, text, title, flags)
294 bh 316 dlg.CenterOnParent()
295 bh 20 result = dlg.ShowModal()
296     dlg.Destroy()
297     return result
298    
299 bh 31 def init_dialogs(self):
300     """Initialize the dialog handling"""
301     # The mainwindow maintains a dict mapping names to open
302     # non-modal dialogs. The dialogs are put into this dict when
303     # they're created and removed when they're closed
304     self.dialogs = {}
305    
306     def add_dialog(self, name, dialog):
307     if self.dialogs.has_key(name):
308 jan 374 raise RuntimeError(_("The Dialog named %s is already open") % name)
309 bh 31 self.dialogs[name] = dialog
310    
311     def dialog_open(self, name):
312     return self.dialogs.has_key(name)
313    
314     def remove_dialog(self, name):
315     del self.dialogs[name]
316    
317     def get_open_dialog(self, name):
318     return self.dialogs.get(name)
319    
320 bh 123 def view_position_changed(self):
321     pos = self.canvas.CurrentPosition()
322     if pos is not None:
323     text = "(%10.10g, %10.10g)" % pos
324     else:
325     text = ""
326 bh 321 self.set_position_text(text)
327    
328     def set_position_text(self, text):
329     """Set the statusbar text showing the current position.
330    
331     By default the text is shown in field 0 of the status bar.
332     Override this method in derived classes to put it into a
333     different field of the statusbar.
334     """
335 bh 123 self.SetStatusText(text)
336    
337 bh 58 def save_modified_session(self, can_veto = 1):
338     """If the current session has been modified, ask the user
339     whether to save it and do so if requested. Return the outcome of
340     the dialog (either wxID_OK, wxID_CANCEL or wxID_NO). If the
341     dialog wasn't run return wxID_NO.
342    
343     If the can_veto parameter is true (default) the dialog includes
344     a cancel button, otherwise not.
345     """
346 bh 227 if self.application.session.WasModified():
347 bh 58 flags = wxYES_NO | wxICON_QUESTION
348     if can_veto:
349     flags = flags | wxCANCEL
350 jan 374 result = self.RunMessageBox(_("Exit"),
351     _("The session has been modified."
352 bh 58 " Do you want to save it?"),
353     flags)
354     if result == wxID_YES:
355     self.SaveSession()
356     else:
357     result = wxID_NO
358     return result
359    
360 jonathan 487 def prepare_new_session(self):
361     for d in self.dialogs.values():
362     if not isinstance(d, tree.SessionTreeView):
363 jonathan 502 d.Close()
364 jonathan 487
365 bh 6 def NewSession(self):
366 jonathan 937 if self.save_modified_session() != wxID_CANCEL:
367     self.prepare_new_session()
368     self.application.SetSession(create_empty_session())
369 bh 6
370     def OpenSession(self):
371 jonathan 937 if self.save_modified_session() != wxID_CANCEL:
372     dlg = wxFileDialog(self, _("Open Session"), ".", "",
373     "Thuban Session File (*.thuban)|*.thuban",
374     wxOPEN)
375     if dlg.ShowModal() == wxID_OK:
376     self.prepare_new_session()
377     self.application.OpenSession(dlg.GetPath())
378     dlg.Destroy()
379 bh 6
380     def SaveSession(self):
381 bh 227 if self.application.session.filename == None:
382 jan 102 self.SaveSessionAs()
383 jonathan 487 else:
384     self.application.SaveSession()
385 bh 6
386     def SaveSessionAs(self):
387 jonathan 431 dlg = wxFileDialog(self, _("Save Session As"), ".", "",
388 jonathan 879 "Thuban Session File (*.thuban)|*.thuban",
389     wxSAVE|wxOVERWRITE_PROMPT)
390 bh 6 if dlg.ShowModal() == wxID_OK:
391 bh 227 self.application.session.SetFilename(dlg.GetPath())
392     self.application.SaveSession()
393 bh 6 dlg.Destroy()
394    
395     def Exit(self):
396 jonathan 621 self.Close(False)
397 bh 6
398 frank 951 def OnClose(self, event):
399 bh 58 result = self.save_modified_session(can_veto = event.CanVeto())
400     if result == wxID_CANCEL:
401 bh 6 event.Veto()
402     else:
403 bh 307 # FIXME: it would be better to tie the unsubscription to
404     # wx's destroy event, but that isn't implemented for wxGTK
405     # yet.
406     self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
407 jonathan 974 DockFrame.OnClose(self, event)
408 frank 1056 for dlg in self.dialogs.values():
409     dlg.Destroy()
410     self.canvas.Destroy()
411 bh 6 self.Destroy()
412    
413     def SetMap(self, map):
414     self.canvas.SetMap(map)
415 jonathan 653 self.__SetTitle(map.Title())
416 bh 6
417 jonathan 768 dialog = self.FindRegisteredDock("legend")
418     if dialog is not None:
419     dialog.GetPanel().SetMap(self.Map())
420    
421 bh 310 def Map(self):
422     """Return the map displayed by this mainwindow"""
423 jonathan 563
424 bh 310 return self.canvas.Map()
425    
426 bh 622 def ToggleSessionTree(self):
427     """If the session tree is shown close it otherwise create a new tree"""
428 bh 37 name = "session_tree"
429     dialog = self.get_open_dialog(name)
430     if dialog is None:
431 bh 227 dialog = tree.SessionTreeView(self, self.application, name)
432 bh 37 self.add_dialog(name, dialog)
433 jonathan 512 dialog.Show(True)
434 bh 37 else:
435 bh 622 dialog.Close()
436 bh 37
437 bh 622 def SessionTreeShown(self):
438     """Return true iff the session tree is currently shown"""
439     return self.get_open_dialog("session_tree") is not None
440 jonathan 517
441 bh 6 def About(self):
442 jan 374 self.RunMessageBox(_("About"),
443 frank 923 _("Thuban %s\n"
444 jonathan 517 #"Build Date: %s\n"
445 frank 923 "using:\n"
446     " %s\n"
447     " %s\n\n"
448 jonathan 517 "Thuban is a program for\n"
449 bh 20 "exploring geographic data.\n"
450 jan 374 "Copyright (C) 2001-2003 Intevation GmbH.\n"
451 jonathan 517 "Thuban is licensed under the GNU GPL"
452 frank 923 % (Thuban.version.longversion,
453     "wxPython %s" % wxPython_version,
454     "Python %d.%d.%d" % sys.version_info[:3]
455     )),
456     # % __ThubanVersion__), #__BuildDate__)),
457 bh 20 wxOK | wxICON_INFORMATION)
458 bh 6
459     def AddLayer(self):
460 jan 374 dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
461 bh 6 wxOPEN)
462     if dlg.ShowModal() == wxID_OK:
463     filename = dlg.GetPath()
464     title = os.path.splitext(os.path.basename(filename))[0]
465 bh 18 map = self.canvas.Map()
466     has_layers = map.HasLayers()
467 bh 20 try:
468 jonathan 963 store = self.application.Session().OpenShapefile(filename)
469 bh 20 except IOError:
470     # the layer couldn't be opened
471 jan 374 self.RunMessageBox(_("Add Layer"),
472     _("Can't open the file '%s'.") % filename)
473 bh 20 else:
474 jonathan 963 layer = Layer(title, store)
475     map.AddLayer(layer)
476 bh 20 if not has_layers:
477 bh 535 # if we're adding a layer to an empty map, fit the
478 bh 20 # new map to the window
479     self.canvas.FitMapToWindow()
480 bh 6 dlg.Destroy()
481    
482 jonathan 937 def AddRasterLayer(self):
483     dlg = wxFileDialog(self, _("Select an image file"), ".", "", "*.*",
484     wxOPEN)
485     if dlg.ShowModal() == wxID_OK:
486     filename = dlg.GetPath()
487     title = os.path.splitext(os.path.basename(filename))[0]
488     map = self.canvas.Map()
489     has_layers = map.HasLayers()
490     try:
491 jonathan 963 layer = RasterLayer(title, filename)
492 jonathan 937 except IOError:
493     # the layer couldn't be opened
494     self.RunMessageBox(_("Add Image Layer"),
495     _("Can't open the file '%s'.") % filename)
496     else:
497 jonathan 963 map.AddLayer(layer)
498 jonathan 937 if not has_layers:
499     # if we're adding a layer to an empty map, fit the
500     # new map to the window
501     self.canvas.FitMapToWindow()
502     dlg.Destroy()
503    
504 bh 6 def RemoveLayer(self):
505     layer = self.current_layer()
506     if layer is not None:
507     self.canvas.Map().RemoveLayer(layer)
508    
509 bh 299 def CanRemoveLayer(self):
510     """Return true if the currently selected layer can be deleted.
511    
512 jonathan 621 If no layer is selected return False.
513 bh 299
514     The return value of this method determines whether the remove
515     layer command is sensitive in menu.
516     """
517     layer = self.current_layer()
518     if layer is not None:
519     return self.canvas.Map().CanRemoveLayer(layer)
520 jonathan 621 return False
521 bh 299
522 bh 6 def RaiseLayer(self):
523     layer = self.current_layer()
524     if layer is not None:
525     self.canvas.Map().RaiseLayer(layer)
526 bh 222
527 bh 6 def LowerLayer(self):
528     layer = self.current_layer()
529     if layer is not None:
530     self.canvas.Map().LowerLayer(layer)
531    
532     def current_layer(self):
533     """Return the currently selected layer.
534    
535     If no layer is selected, return None
536     """
537 bh 535 return self.canvas.SelectedLayer()
538 bh 6
539     def has_selected_layer(self):
540     """Return true if a layer is currently selected"""
541 bh 535 return self.canvas.HasSelectedLayer()
542 bh 6
543 jonathan 829 def has_selected_shapes(self):
544     """Return true if a shape is currently selected"""
545     return self.canvas.HasSelectedShapes()
546    
547 bh 6 def HideLayer(self):
548     layer = self.current_layer()
549     if layer is not None:
550     layer.SetVisible(0)
551    
552     def ShowLayer(self):
553     layer = self.current_layer()
554     if layer is not None:
555     layer.SetVisible(1)
556    
557     def LayerShowTable(self):
558     layer = self.current_layer()
559     if layer is not None:
560 bh 31 table = layer.table
561     name = "table_view" + str(id(table))
562     dialog = self.get_open_dialog(name)
563     if dialog is None:
564 bh 535 dialog = tableview.LayerTableFrame(self, name,
565 jan 1023 _("Layer Table: %s") % layer.Title(),
566     layer, table)
567 bh 31 self.add_dialog(name, dialog)
568 jan 1035 dialog.Show(True)
569 bh 31 else:
570     # FIXME: bring dialog to front here
571     pass
572 bh 6
573 jonathan 729 def MapProjection(self):
574 bh 6
575 jonathan 729 name = "map_projection"
576 jonathan 713 dialog = self.get_open_dialog(name)
577    
578     if dialog is None:
579     map = self.canvas.Map()
580 jonathan 750 dialog = projdialog.ProjFrame(self, name,
581     _("Map Projection: %s") % map.Title(), map)
582 jonathan 713 self.add_dialog(name, dialog)
583     dialog.Show()
584     dialog.Raise()
585    
586 jonathan 729 def LayerProjection(self):
587    
588     layer = self.current_layer()
589    
590     name = "layer_projection" + str(id(layer))
591     dialog = self.get_open_dialog(name)
592    
593     if dialog is None:
594     map = self.canvas.Map()
595 jonathan 750 dialog = projdialog.ProjFrame(self, name,
596     _("Layer Projection: %s") % layer.Title(), layer)
597 jonathan 729 self.add_dialog(name, dialog)
598     dialog.Show()
599     dialog.Raise()
600    
601 jonathan 640 def LayerEditProperties(self):
602 jonathan 363
603 jonathan 487 #
604     # the menu option for this should only be available if there
605     # is a current layer, so we don't need to check if the
606     # current layer is None
607     #
608    
609     layer = self.current_layer()
610 jonathan 640 self.OpenLayerProperties(layer)
611 jonathan 550
612 jonathan 640 def OpenLayerProperties(self, layer, group = None):
613     name = "layer_properties" + str(id(layer))
614 jonathan 487 dialog = self.get_open_dialog(name)
615    
616     if dialog is None:
617 jonathan 633 dialog = Classifier(self, name, layer, group)
618 jonathan 487 self.add_dialog(name, dialog)
619     dialog.Show()
620 jonathan 573 dialog.Raise()
621 jonathan 487
622 jonathan 879 def LayerJoinTable(self):
623 bh 1072 layer = self.canvas.SelectedLayer()
624     if layer is not None:
625     dlg = JoinDialog(self, _("Join Layer with Table"),
626     self.application.session,
627     layer = layer)
628     dlg.ShowModal()
629 jonathan 550
630 jonathan 879 def LayerUnjoinTable(self):
631 bh 1074 layer = self.canvas.SelectedLayer()
632     if layer is not None:
633     orig_store = layer.ShapeStore().OrigShapeStore()
634     if orig_store:
635     layer.SetShapeStore(orig_store)
636 jonathan 879
637 jonathan 621 def ShowLegend(self):
638 bh 622 if not self.LegendShown():
639     self.ToggleLegend()
640    
641     def ToggleLegend(self):
642     """Show the legend if it's not shown otherwise hide it again"""
643 jonathan 550 name = "legend"
644 jonathan 573 dialog = self.FindRegisteredDock(name)
645 jonathan 550
646     if dialog is None:
647 jonathan 640 dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
648 jonathan 573 legend.LegendPanel(dialog, None, self)
649 jonathan 580 dialog.Dock()
650 bh 622 dialog.GetPanel().SetMap(self.Map())
651     dialog.Show()
652     else:
653     dialog.Show(not dialog.IsShown())
654 jonathan 563
655 bh 622 def LegendShown(self):
656     """Return true iff the legend is currently open"""
657     dialog = self.FindRegisteredDock("legend")
658     return dialog is not None and dialog.IsShown()
659 jonathan 563
660 jonathan 879 def TableOpen(self):
661     dlg = wxFileDialog(self, _("Open Table"), ".", "",
662 bh 1037 _("DBF Files (*.dbf)") + "|*.dbf|" +
663     #_("CSV Files (*.csv)") + "|*.csv|" +
664     _("All Files (*.*)") + "|*.*",
665 jonathan 879 wxOPEN)
666     if dlg.ShowModal() == wxID_OK:
667 bh 1054 filename = dlg.GetPath()
668     dlg.Destroy()
669     try:
670     table = self.application.session.OpenTableFile(filename)
671     except IOError:
672     # the layer couldn't be opened
673     self.RunMessageBox(_("Open Table"),
674     _("Can't open the file '%s'.") % filename)
675     else:
676     self.ShowTableView(table)
677 jonathan 879
678     def TableClose(self):
679 bh 1068 tables = self.application.session.UnreferencedTables()
680 jonathan 879
681 jan 1084 lst = [(t.Title(), t) for t in tables]
682     lst.sort()
683     titles = [i[0] for i in lst]
684 bh 1068 dlg = wxMultipleChoiceDialog(self, _("Pick the tables to close:"),
685 jan 1084 _("Close Table"), titles,
686     size = (400, 300),
687     style = wxDEFAULT_DIALOG_STYLE |
688     wxRESIZE_BORDER)
689 bh 1068 if dlg.ShowModal() == wxID_OK:
690     for i in dlg.GetValue():
691 jan 1084 self.application.session.RemoveTable(lst[i][1])
692 bh 1068
693    
694 jonathan 879 def TableShow(self):
695 jan 1014 """Offer a multi-selection dialog for tables to be displayed
696 bh 1054
697 jan 1014 The windows for the selected tables are opened or brought to
698     the front.
699     """
700     tables = self.application.session.Tables()
701 jonathan 879
702 jan 1084 lst = [(t.Title(), t) for t in tables]
703     lst.sort()
704     titles = [i[0] for i in lst]
705 jan 1014 dlg = wxMultipleChoiceDialog(self, _("Pick the table to show:"),
706 jan 1084 _("Show Table"), titles,
707 frank 1076 size = (400,300),
708     style = wxDEFAULT_DIALOG_STYLE |
709     wxRESIZE_BORDER)
710 jan 1014 if (dlg.ShowModal() == wxID_OK):
711     for i in dlg.GetValue():
712 jan 1023 # XXX: if the table belongs to a layer, open a
713     # LayerTableFrame instead of QueryTableFrame
714 jan 1084 self.ShowTableView(lst[i][1])
715 jan 1014
716 jonathan 879 def TableJoin(self):
717     dlg = JoinDialog(self, _("Join Tables"), self.application.session)
718 frank 1001 dlg.ShowModal()
719 jonathan 879
720 bh 1054 def ShowTableView(self, table):
721     """Open a table view for the table and optionally"""
722     name = "table_view%d" % id(table)
723     dialog = self.get_open_dialog(name)
724     if dialog is None:
725     dialog = tableview.QueryTableFrame(self, name,
726     _("Table: %s") % table.Title(),
727     table)
728     self.add_dialog(name, dialog)
729     dialog.Show(True)
730     # FIXME: else bring dialog to front
731    
732 bh 6 def ZoomInTool(self):
733     self.canvas.ZoomInTool()
734    
735     def ZoomOutTool(self):
736     self.canvas.ZoomOutTool()
737    
738     def PanTool(self):
739     self.canvas.PanTool()
740    
741     def IdentifyTool(self):
742     self.canvas.IdentifyTool()
743 bh 49 self.identify_view_on_demand(None, None)
744 bh 6
745     def LabelTool(self):
746     self.canvas.LabelTool()
747    
748     def FullExtent(self):
749     self.canvas.FitMapToWindow()
750    
751 jonathan 821 def FullLayerExtent(self):
752     self.canvas.FitLayerToWindow(self.current_layer())
753    
754 jonathan 829 def FullSelectionExtent(self):
755     self.canvas.FitSelectedToWindow()
756    
757 frank 911 def ExportMap(self):
758     self.canvas.Export()
759    
760 bh 6 def PrintMap(self):
761     self.canvas.Print()
762    
763 jonathan 653 def RenameMap(self):
764     dlg = wxTextEntryDialog(self, "Map Title: ", "Rename Map",
765     self.Map().Title())
766     if dlg.ShowModal() == wxID_OK:
767     title = dlg.GetValue()
768     if title != "":
769     self.Map().SetTitle(title)
770     self.__SetTitle(title)
771    
772     dlg.Destroy()
773    
774 bh 535 def identify_view_on_demand(self, layer, shapes):
775 bh 787 """Subscribed to the canvas' SHAPES_SELECTED message
776    
777     If the current tool is the identify tool, at least one shape is
778     selected and the identify dialog is not shown, show the dialog.
779     """
780     # If the selection has become empty we don't need to do
781     # anything. Otherwise it could happen that the dialog was popped
782     # up when the selection became empty, e.g. when a new selection
783     # is opened while the identify tool is active and dialog had
784     # been closed
785     if not shapes:
786     return
787    
788 bh 31 name = "identify_view"
789     if self.canvas.CurrentTool() == "IdentifyTool":
790     if not self.dialog_open(name):
791 bh 535 dialog = identifyview.IdentifyView(self, name)
792 bh 31 self.add_dialog(name, dialog)
793 jonathan 563 dialog.Show(True)
794 bh 31 else:
795 bh 33 # FIXME: bring dialog to front?
796 bh 31 pass
797 bh 6
798 jonathan 653 def __SetTitle(self, title):
799     self.SetTitle("Thuban - " + title)
800    
801 bh 6 #
802     # Define all the commands available in the main window
803     #
804    
805    
806     # Helper functions to define common command implementations
807     def call_method(context, methodname, *args):
808 bh 222 """Call the mainwindow's method methodname with args *args"""
809     apply(getattr(context.mainwindow, methodname), args)
810 bh 6
811 jan 110 def _method_command(name, title, method, helptext = "",
812 bh 622 icon = "", sensitive = None, checked = None):
813 bh 222 """Add a command implemented by a method of the mainwindow object"""
814 bh 6 registry.Add(Command(name, title, call_method, args=(method,),
815 jan 110 helptext = helptext, icon = icon,
816 bh 622 sensitive = sensitive, checked = checked))
817 jan 110
818 bh 270 def make_check_current_tool(toolname):
819     """Return a function that tests if the currently active tool is toolname
820    
821     The returned function can be called with the context and returns
822     true iff the currently active tool's name is toolname. It's directly
823     usable as the 'checked' callback of a command.
824     """
825     def check_current_tool(context, name=toolname):
826     return context.mainwindow.canvas.CurrentTool() == name
827     return check_current_tool
828    
829 bh 6 def _tool_command(name, title, method, toolname, helptext = "",
830 bh 310 icon = "", sensitive = None):
831 bh 6 """Add a tool command"""
832 bh 357 registry.Add(ToolCommand(name, title, call_method, args=(method,),
833     helptext = helptext, icon = icon,
834     checked = make_check_current_tool(toolname),
835     sensitive = sensitive))
836 bh 6
837     def _has_selected_layer(context):
838     """Return true if a layer is selected in the context"""
839 bh 222 return context.mainwindow.has_selected_layer()
840 bh 6
841 jonathan 829 def _has_selected_shapes(context):
842     """Return true if a layer is selected in the context"""
843     return context.mainwindow.has_selected_shapes()
844    
845 bh 299 def _can_remove_layer(context):
846     return context.mainwindow.CanRemoveLayer()
847    
848 jan 264 def _has_tree_window_shown(context):
849     """Return true if the tree window is shown"""
850 bh 622 return context.mainwindow.SessionTreeShown()
851 jan 264
852 bh 310 def _has_visible_map(context):
853     """Return true iff theres a visible map in the mainwindow.
854    
855     A visible map is a map with at least one visible layer."""
856     map = context.mainwindow.Map()
857     if map is not None:
858     for layer in map.Layers():
859     if layer.Visible():
860     return 1
861     return 0
862    
863 jonathan 550 def _has_legend_shown(context):
864     """Return true if the legend window is shown"""
865 bh 622 return context.mainwindow.LegendShown()
866 bh 310
867 jonathan 550
868 bh 6 # File menu
869 jan 374 _method_command("new_session", _("&New Session"), "NewSession")
870 jonathan 815 _method_command("open_session", _("&Open Session..."), "OpenSession")
871 jan 374 _method_command("save_session", _("&Save Session"), "SaveSession")
872 jonathan 815 _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs")
873 bh 622 _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
874     checked = _has_tree_window_shown)
875     _method_command("toggle_legend", _("Legend"), "ToggleLegend",
876     checked = _has_legend_shown)
877 jan 374 _method_command("exit", _("E&xit"), "Exit")
878 bh 6
879     # Help menu
880 jonathan 815 _method_command("help_about", _("&About..."), "About")
881 bh 6
882    
883     # Map menu
884 jonathan 815 _method_command("map_projection", _("Pro&jection..."), "MapProjection")
885 bh 6
886 jan 374 _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
887     helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
888 bh 310 sensitive = _has_visible_map)
889 jan 374 _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
890     helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
891 bh 310 sensitive = _has_visible_map)
892 jan 374 _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
893     helptext = _("Switch to map-mode 'pan'"), icon = "pan",
894 bh 310 sensitive = _has_visible_map)
895 jan 374 _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
896     "IdentifyTool",
897     helptext = _("Switch to map-mode 'identify'"), icon = "identify",
898 bh 310 sensitive = _has_visible_map)
899 jan 374 _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
900     helptext = _("Add/Remove labels"), icon = "label",
901 bh 310 sensitive = _has_visible_map)
902 jan 374 _method_command("map_full_extent", _("&Full extent"), "FullExtent",
903     helptext = _("Full Extent"), icon = "fullextent",
904 bh 310 sensitive = _has_visible_map)
905 jonathan 821 _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
906 jonathan 829 helptext = _("Full Layer Extent"), icon = "fulllayerextent",
907 jonathan 821 sensitive = _has_selected_layer)
908 jonathan 829 _method_command("selected_full_extent", _("&Full selection extent"), "FullSelectionExtent",
909     helptext = _("Full Selection Extent"), icon = "fullselextent",
910     sensitive = _has_selected_shapes)
911 frank 911 _method_command("map_export", _("E&xport"), "ExportMap",
912     helptext = _("Export the map to file"))
913 jan 374 _method_command("map_print", _("Prin&t"), "PrintMap",
914     helptext = _("Print the map"))
915 jonathan 815 _method_command("map_rename", _("&Rename..."), "RenameMap",
916 jonathan 653 helptext = _("Rename the map"))
917 jonathan 815 _method_command("layer_add", _("&Add Layer..."), "AddLayer",
918 jan 374 helptext = _("Add a new layer to active map"))
919 jonathan 937 _method_command("rasterlayer_add", _("&Add Image Layer..."), "AddRasterLayer",
920     helptext = _("Add a new image layer to active map"))
921 jan 374 _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
922     helptext = _("Remove selected layer(s)"),
923 bh 299 sensitive = _can_remove_layer)
924 jonathan 729
925     # Layer menu
926 jonathan 815 _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
927 jonathan 729 sensitive = _has_selected_layer)
928 jan 374 _method_command("layer_raise", _("&Raise"), "RaiseLayer",
929     helptext = _("Raise selected layer(s)"),
930 bh 6 sensitive = _has_selected_layer)
931 jan 374 _method_command("layer_lower", _("&Lower"), "LowerLayer",
932     helptext = _("Lower selected layer(s)"),
933 bh 6 sensitive = _has_selected_layer)
934 jan 374 _method_command("layer_show", _("&Show"), "ShowLayer",
935     helptext = _("Make selected layer(s) visible"),
936 bh 6 sensitive = _has_selected_layer)
937 jan 374 _method_command("layer_hide", _("&Hide"), "HideLayer",
938     helptext = _("Make selected layer(s) unvisible"),
939 bh 6 sensitive = _has_selected_layer)
940 jan 374 _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
941     helptext = _("Show the selected layer's table"),
942 bh 6 sensitive = _has_selected_layer)
943 jonathan 815 _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
944 jonathan 363 sensitive = _has_selected_layer)
945 jonathan 879 _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
946     sensitive = _has_selected_layer)
947 bh 1074
948     def _can_unjoin(context):
949 bh 1080 """Return whether the Layer/Unjoin command can be executed.
950    
951     This is the case if a layer is selected and that layer has a
952     shapestore that has an original shapestore.
953     """
954 bh 1074 layer = context.mainwindow.SelectedLayer()
955 bh 1080 if layer is None:
956     return 0
957     getstore = getattr(layer, "ShapeStore", None)
958     if getstore is not None:
959     return getstore().OrigShapeStore() is not None
960     else:
961     return 0
962 jonathan 879 _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
963 bh 1074 sensitive = _can_unjoin)
964 bh 188
965 jonathan 879 # Table menu
966     _method_command("table_open", _("&Open..."), "TableOpen")
967 bh 1070 _method_command("table_close", _("&Close"), "TableClose",
968     sensitive = lambda context: bool(context.session.UnreferencedTables()))
969 jonathan 879 _method_command("table_show", _("&Show"), "TableShow")
970     _method_command("table_join", _("&Join..."), "TableJoin")
971    
972 frank 911 # Export only under Windows ...
973 jonathan 937 map_menu = ["layer_add", "rasterlayer_add", "layer_remove", "map_rename",
974 bh 188 None,
975     "map_projection",
976     None,
977     "map_zoom_in_tool", "map_zoom_out_tool",
978 jonathan 829 "map_pan_tool",
979     "map_full_extent",
980     "layer_full_extent",
981     "selected_full_extent",
982 bh 188 None,
983 jonathan 815 "map_identify_tool", "map_label_tool",
984 bh 188 None,
985 bh 624 "toggle_legend",
986 frank 911 None]
987     if wxPlatform == '__WXMSW__':
988     map_menu.append("map_export")
989     map_menu.append("map_print")
990    
991     # the menu structure
992     main_menu = Menu("<main>", "<main>",
993     [Menu("file", _("&File"),
994     ["new_session", "open_session", None,
995     "save_session", "save_session_as", None,
996     "toggle_session_tree", None,
997     "exit"]),
998     Menu("map", _("&Map"), map_menu),
999 jan 374 Menu("layer", _("&Layer"),
1000 jonathan 640 ["layer_raise", "layer_lower",
1001 bh 188 None,
1002     "layer_show", "layer_hide",
1003     None,
1004 jonathan 879 "layer_projection",
1005     None,
1006 jonathan 363 "layer_show_table",
1007 jonathan 879 "layer_jointable",
1008     "layer_unjointable",
1009 jonathan 363 None,
1010 jonathan 815 "layer_properties"]),
1011 jonathan 879 Menu("table", _("&Table"),
1012     ["table_open", "table_close",
1013     None,
1014 bh 1052 "table_show",
1015 jonathan 879 None,
1016     "table_join"]),
1017 jan 374 Menu("help", _("&Help"),
1018 bh 188 ["help_about"])])
1019 bh 191
1020     # the main toolbar
1021    
1022     main_toolbar = Menu("<toolbar>", "<toolbar>",
1023 frank 351 ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
1024 jonathan 829 "map_full_extent",
1025     "layer_full_extent",
1026     "selected_full_extent",
1027     None,
1028 frank 351 "map_identify_tool", "map_label_tool"])

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26