/[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 951 - (hide annotations)
Wed May 21 14:20:32 2003 UTC (21 years, 9 months ago) by frank
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 35306 byte(s)
(MainWindow): Renamed _OnClose() back to OnClose() to keep in sync
with extensions. Internally Thuban still uses "underscored" names.

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     import Thuban
25 frank 923 import Thuban.version
26    
27 jan 374 from Thuban import _
28 bh 188 from Thuban.Model.session import create_empty_session
29 jonathan 937 from Thuban.Model.layer import Layer, RasterLayer
30 bh 6 from Thuban.Model.color import Color
31     from Thuban.Model.proj import Projection
32    
33     import view
34     import tree
35     import proj4dialog
36     import tableview, identifyview
37 jonathan 633 from Thuban.UI.classifier import Classifier
38 jonathan 550 import legend
39 bh 188 from menu import Menu
40 bh 6
41 bh 222 from context import Context
42 bh 357 from command import registry, Command, ToolCommand
43 bh 704 from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION
44 bh 6
45 bh 704 from Thuban.UI.dock import DockFrame
46 jonathan 879 from Thuban.UI.join import JoinDialog
47 bh 6
48 jonathan 653 import resource
49 jonathan 563
50 jonathan 713 import projdialog
51 jonathan 653
52 bh 6
53 jonathan 713
54 jonathan 573 class MainWindow(DockFrame):
55 bh 6
56 bh 535 # Some messages that can be subscribed/unsubscribed directly through
57     # the MapCanvas come in fact from other objects. This is a map to
58     # map those messages to the names of the instance variables they
59     # actually come from. This delegation is implemented in the
60     # Subscribe and unsubscribed methods
61     delegated_messages = {LAYER_SELECTED: "canvas",
62     SHAPES_SELECTED: "canvas"}
63    
64     # Methods delegated to some instance variables. The delegation is
65     # implemented in the __getattr__ method.
66     delegated_methods = {"SelectLayer": "canvas",
67     "SelectShapes": "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 580 DockFrame._OnClose(self, event)
408 bh 6 self.Destroy()
409    
410     def SetMap(self, map):
411     self.canvas.SetMap(map)
412 jonathan 653 self.__SetTitle(map.Title())
413 bh 6
414 jonathan 768 dialog = self.FindRegisteredDock("legend")
415     if dialog is not None:
416     dialog.GetPanel().SetMap(self.Map())
417    
418 bh 310 def Map(self):
419     """Return the map displayed by this mainwindow"""
420 jonathan 563
421 bh 310 return self.canvas.Map()
422    
423 bh 622 def ToggleSessionTree(self):
424     """If the session tree is shown close it otherwise create a new tree"""
425 bh 37 name = "session_tree"
426     dialog = self.get_open_dialog(name)
427     if dialog is None:
428 bh 227 dialog = tree.SessionTreeView(self, self.application, name)
429 bh 37 self.add_dialog(name, dialog)
430 jonathan 512 dialog.Show(True)
431 bh 37 else:
432 bh 622 dialog.Close()
433 bh 37
434 bh 622 def SessionTreeShown(self):
435     """Return true iff the session tree is currently shown"""
436     return self.get_open_dialog("session_tree") is not None
437 jonathan 517
438 bh 6 def About(self):
439 jan 374 self.RunMessageBox(_("About"),
440 frank 923 _("Thuban %s\n"
441 jonathan 517 #"Build Date: %s\n"
442 frank 923 "using:\n"
443     " %s\n"
444     " %s\n\n"
445 jonathan 517 "Thuban is a program for\n"
446 bh 20 "exploring geographic data.\n"
447 jan 374 "Copyright (C) 2001-2003 Intevation GmbH.\n"
448 jonathan 517 "Thuban is licensed under the GNU GPL"
449 frank 923 % (Thuban.version.longversion,
450     "wxPython %s" % wxPython_version,
451     "Python %d.%d.%d" % sys.version_info[:3]
452     )),
453     # % __ThubanVersion__), #__BuildDate__)),
454 bh 20 wxOK | wxICON_INFORMATION)
455 bh 6
456     def AddLayer(self):
457 jan 374 dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
458 bh 6 wxOPEN)
459     if dlg.ShowModal() == wxID_OK:
460     filename = dlg.GetPath()
461     title = os.path.splitext(os.path.basename(filename))[0]
462 bh 723 store = self.application.Session().OpenShapefile(filename)
463     layer = Layer(title, store)
464 bh 18 map = self.canvas.Map()
465     has_layers = map.HasLayers()
466 bh 20 try:
467     map.AddLayer(layer)
468     except IOError:
469     # the layer couldn't be opened
470 jan 374 self.RunMessageBox(_("Add Layer"),
471     _("Can't open the file '%s'.") % filename)
472 bh 20 else:
473     if not has_layers:
474 bh 535 # if we're adding a layer to an empty map, fit the
475 bh 20 # new map to the window
476     self.canvas.FitMapToWindow()
477 bh 6 dlg.Destroy()
478    
479 jonathan 937 def AddRasterLayer(self):
480     dlg = wxFileDialog(self, _("Select an image file"), ".", "", "*.*",
481     wxOPEN)
482     if dlg.ShowModal() == wxID_OK:
483     filename = dlg.GetPath()
484     title = os.path.splitext(os.path.basename(filename))[0]
485     layer = RasterLayer(title, filename)
486     map = self.canvas.Map()
487     has_layers = map.HasLayers()
488     try:
489     map.AddLayer(layer)
490     except IOError:
491     # the layer couldn't be opened
492     self.RunMessageBox(_("Add Image Layer"),
493     _("Can't open the file '%s'.") % filename)
494     else:
495     if not has_layers:
496     # if we're adding a layer to an empty map, fit the
497     # new map to the window
498     self.canvas.FitMapToWindow()
499     dlg.Destroy()
500    
501 bh 6 def RemoveLayer(self):
502     layer = self.current_layer()
503     if layer is not None:
504     self.canvas.Map().RemoveLayer(layer)
505    
506 bh 299 def CanRemoveLayer(self):
507     """Return true if the currently selected layer can be deleted.
508    
509 jonathan 621 If no layer is selected return False.
510 bh 299
511     The return value of this method determines whether the remove
512     layer command is sensitive in menu.
513     """
514     layer = self.current_layer()
515     if layer is not None:
516     return self.canvas.Map().CanRemoveLayer(layer)
517 jonathan 621 return False
518 bh 299
519 bh 6 def RaiseLayer(self):
520     layer = self.current_layer()
521     if layer is not None:
522     self.canvas.Map().RaiseLayer(layer)
523 bh 222
524 bh 6 def LowerLayer(self):
525     layer = self.current_layer()
526     if layer is not None:
527     self.canvas.Map().LowerLayer(layer)
528    
529     def current_layer(self):
530     """Return the currently selected layer.
531    
532     If no layer is selected, return None
533     """
534 bh 535 return self.canvas.SelectedLayer()
535 bh 6
536     def has_selected_layer(self):
537     """Return true if a layer is currently selected"""
538 bh 535 return self.canvas.HasSelectedLayer()
539 bh 6
540 jonathan 829 def has_selected_shapes(self):
541     """Return true if a shape is currently selected"""
542     return self.canvas.HasSelectedShapes()
543    
544 bh 6 def HideLayer(self):
545     layer = self.current_layer()
546     if layer is not None:
547     layer.SetVisible(0)
548    
549     def ShowLayer(self):
550     layer = self.current_layer()
551     if layer is not None:
552     layer.SetVisible(1)
553    
554     def LayerShowTable(self):
555     layer = self.current_layer()
556     if layer is not None:
557 bh 31 table = layer.table
558     name = "table_view" + str(id(table))
559     dialog = self.get_open_dialog(name)
560     if dialog is None:
561 bh 535 dialog = tableview.LayerTableFrame(self, name,
562     _("Table: %s") % layer.Title(),
563 bh 278 layer, table)
564 bh 31 self.add_dialog(name, dialog)
565     dialog.Show(true)
566     else:
567     # FIXME: bring dialog to front here
568     pass
569 bh 6
570 jonathan 729 def MapProjection(self):
571 bh 6
572 jonathan 729 name = "map_projection"
573 jonathan 713 dialog = self.get_open_dialog(name)
574    
575     if dialog is None:
576     map = self.canvas.Map()
577 jonathan 750 dialog = projdialog.ProjFrame(self, name,
578     _("Map Projection: %s") % map.Title(), map)
579 jonathan 713 self.add_dialog(name, dialog)
580     dialog.Show()
581     dialog.Raise()
582    
583 jonathan 729 def LayerProjection(self):
584    
585     layer = self.current_layer()
586    
587     name = "layer_projection" + str(id(layer))
588     dialog = self.get_open_dialog(name)
589    
590     if dialog is None:
591     map = self.canvas.Map()
592 jonathan 750 dialog = projdialog.ProjFrame(self, name,
593     _("Layer Projection: %s") % layer.Title(), layer)
594 jonathan 729 self.add_dialog(name, dialog)
595     dialog.Show()
596     dialog.Raise()
597    
598 jonathan 640 def LayerEditProperties(self):
599 jonathan 363
600 jonathan 487 #
601     # the menu option for this should only be available if there
602     # is a current layer, so we don't need to check if the
603     # current layer is None
604     #
605    
606     layer = self.current_layer()
607 jonathan 640 self.OpenLayerProperties(layer)
608 jonathan 550
609 jonathan 640 def OpenLayerProperties(self, layer, group = None):
610     name = "layer_properties" + str(id(layer))
611 jonathan 487 dialog = self.get_open_dialog(name)
612    
613     if dialog is None:
614 jonathan 633 dialog = Classifier(self, name, layer, group)
615 jonathan 487 self.add_dialog(name, dialog)
616     dialog.Show()
617 jonathan 573 dialog.Raise()
618 jonathan 487
619 jonathan 879 def LayerJoinTable(self):
620     print "LayerJoinTable"
621 jonathan 550
622 jonathan 879 def LayerUnjoinTable(self):
623     print "LayerUnjoinTable"
624    
625 jonathan 621 def ShowLegend(self):
626 bh 622 if not self.LegendShown():
627     self.ToggleLegend()
628    
629     def ToggleLegend(self):
630     """Show the legend if it's not shown otherwise hide it again"""
631 jonathan 550 name = "legend"
632 jonathan 573 dialog = self.FindRegisteredDock(name)
633 jonathan 550
634     if dialog is None:
635 jonathan 640 dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
636 jonathan 573 legend.LegendPanel(dialog, None, self)
637 jonathan 580 dialog.Dock()
638 bh 622 dialog.GetPanel().SetMap(self.Map())
639     dialog.Show()
640     else:
641     dialog.Show(not dialog.IsShown())
642 jonathan 563
643 bh 622 def LegendShown(self):
644     """Return true iff the legend is currently open"""
645     dialog = self.FindRegisteredDock("legend")
646     return dialog is not None and dialog.IsShown()
647 jonathan 563
648 jonathan 879 def TableOpen(self):
649     print "TableOpen"
650     dlg = wxFileDialog(self, _("Open Table"), ".", "",
651     "DBF Files (*.dbf)|*.dbf|" +
652     "CSV Files (*.csv)|*.csv|" +
653     "All Files (*.*)|*.*",
654     wxOPEN)
655     if dlg.ShowModal() == wxID_OK:
656     #self.application.session.OpenTable(dlg.GetPath())
657     pass
658    
659     dlg.Destroy()
660    
661     def TableClose(self):
662     print "TableClose"
663    
664     def TableShow(self):
665     print "TableShow"
666    
667     def TableHide(self):
668     print "TableHide"
669    
670     def TableJoin(self):
671     print "TableJoin"
672     dlg = JoinDialog(self, _("Join Tables"), self.application.session)
673     if dlg.ShowModal() == wxID_OK:
674     print "OK"
675    
676 bh 6 def ZoomInTool(self):
677     self.canvas.ZoomInTool()
678    
679     def ZoomOutTool(self):
680     self.canvas.ZoomOutTool()
681    
682     def PanTool(self):
683     self.canvas.PanTool()
684    
685     def IdentifyTool(self):
686     self.canvas.IdentifyTool()
687 bh 49 self.identify_view_on_demand(None, None)
688 bh 6
689     def LabelTool(self):
690     self.canvas.LabelTool()
691    
692     def FullExtent(self):
693     self.canvas.FitMapToWindow()
694    
695 jonathan 821 def FullLayerExtent(self):
696     self.canvas.FitLayerToWindow(self.current_layer())
697    
698 jonathan 829 def FullSelectionExtent(self):
699     self.canvas.FitSelectedToWindow()
700    
701 frank 911 def ExportMap(self):
702     self.canvas.Export()
703    
704 bh 6 def PrintMap(self):
705     self.canvas.Print()
706    
707 jonathan 653 def RenameMap(self):
708     dlg = wxTextEntryDialog(self, "Map Title: ", "Rename Map",
709     self.Map().Title())
710     if dlg.ShowModal() == wxID_OK:
711     title = dlg.GetValue()
712     if title != "":
713     self.Map().SetTitle(title)
714     self.__SetTitle(title)
715    
716     dlg.Destroy()
717    
718 bh 535 def identify_view_on_demand(self, layer, shapes):
719 bh 787 """Subscribed to the canvas' SHAPES_SELECTED message
720    
721     If the current tool is the identify tool, at least one shape is
722     selected and the identify dialog is not shown, show the dialog.
723     """
724     # If the selection has become empty we don't need to do
725     # anything. Otherwise it could happen that the dialog was popped
726     # up when the selection became empty, e.g. when a new selection
727     # is opened while the identify tool is active and dialog had
728     # been closed
729     if not shapes:
730     return
731    
732 bh 31 name = "identify_view"
733     if self.canvas.CurrentTool() == "IdentifyTool":
734     if not self.dialog_open(name):
735 bh 535 dialog = identifyview.IdentifyView(self, name)
736 bh 31 self.add_dialog(name, dialog)
737 jonathan 563 dialog.Show(True)
738 bh 31 else:
739 bh 33 # FIXME: bring dialog to front?
740 bh 31 pass
741 bh 6
742 jonathan 653 def __SetTitle(self, title):
743     self.SetTitle("Thuban - " + title)
744    
745 bh 6 #
746     # Define all the commands available in the main window
747     #
748    
749    
750     # Helper functions to define common command implementations
751     def call_method(context, methodname, *args):
752 bh 222 """Call the mainwindow's method methodname with args *args"""
753     apply(getattr(context.mainwindow, methodname), args)
754 bh 6
755 jan 110 def _method_command(name, title, method, helptext = "",
756 bh 622 icon = "", sensitive = None, checked = None):
757 bh 222 """Add a command implemented by a method of the mainwindow object"""
758 bh 6 registry.Add(Command(name, title, call_method, args=(method,),
759 jan 110 helptext = helptext, icon = icon,
760 bh 622 sensitive = sensitive, checked = checked))
761 jan 110
762 bh 270 def make_check_current_tool(toolname):
763     """Return a function that tests if the currently active tool is toolname
764    
765     The returned function can be called with the context and returns
766     true iff the currently active tool's name is toolname. It's directly
767     usable as the 'checked' callback of a command.
768     """
769     def check_current_tool(context, name=toolname):
770     return context.mainwindow.canvas.CurrentTool() == name
771     return check_current_tool
772    
773 bh 6 def _tool_command(name, title, method, toolname, helptext = "",
774 bh 310 icon = "", sensitive = None):
775 bh 6 """Add a tool command"""
776 bh 357 registry.Add(ToolCommand(name, title, call_method, args=(method,),
777     helptext = helptext, icon = icon,
778     checked = make_check_current_tool(toolname),
779     sensitive = sensitive))
780 bh 6
781     def _has_selected_layer(context):
782     """Return true if a layer is selected in the context"""
783 bh 222 return context.mainwindow.has_selected_layer()
784 bh 6
785 jonathan 829 def _has_selected_shapes(context):
786     """Return true if a layer is selected in the context"""
787     return context.mainwindow.has_selected_shapes()
788    
789 bh 299 def _can_remove_layer(context):
790     return context.mainwindow.CanRemoveLayer()
791    
792 jan 264 def _has_tree_window_shown(context):
793     """Return true if the tree window is shown"""
794 bh 622 return context.mainwindow.SessionTreeShown()
795 jan 264
796 bh 310 def _has_visible_map(context):
797     """Return true iff theres a visible map in the mainwindow.
798    
799     A visible map is a map with at least one visible layer."""
800     map = context.mainwindow.Map()
801     if map is not None:
802     for layer in map.Layers():
803     if layer.Visible():
804     return 1
805     return 0
806    
807 jonathan 550 def _has_legend_shown(context):
808     """Return true if the legend window is shown"""
809 bh 622 return context.mainwindow.LegendShown()
810 bh 310
811 jonathan 550
812 bh 6 # File menu
813 jan 374 _method_command("new_session", _("&New Session"), "NewSession")
814 jonathan 815 _method_command("open_session", _("&Open Session..."), "OpenSession")
815 jan 374 _method_command("save_session", _("&Save Session"), "SaveSession")
816 jonathan 815 _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs")
817 bh 622 _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
818     checked = _has_tree_window_shown)
819     _method_command("toggle_legend", _("Legend"), "ToggleLegend",
820     checked = _has_legend_shown)
821 jan 374 _method_command("exit", _("E&xit"), "Exit")
822 bh 6
823     # Help menu
824 jonathan 815 _method_command("help_about", _("&About..."), "About")
825 bh 6
826    
827     # Map menu
828 jonathan 815 _method_command("map_projection", _("Pro&jection..."), "MapProjection")
829 bh 6
830 jan 374 _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
831     helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
832 bh 310 sensitive = _has_visible_map)
833 jan 374 _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
834     helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
835 bh 310 sensitive = _has_visible_map)
836 jan 374 _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
837     helptext = _("Switch to map-mode 'pan'"), icon = "pan",
838 bh 310 sensitive = _has_visible_map)
839 jan 374 _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
840     "IdentifyTool",
841     helptext = _("Switch to map-mode 'identify'"), icon = "identify",
842 bh 310 sensitive = _has_visible_map)
843 jan 374 _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
844     helptext = _("Add/Remove labels"), icon = "label",
845 bh 310 sensitive = _has_visible_map)
846 jan 374 _method_command("map_full_extent", _("&Full extent"), "FullExtent",
847     helptext = _("Full Extent"), icon = "fullextent",
848 bh 310 sensitive = _has_visible_map)
849 jonathan 821 _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
850 jonathan 829 helptext = _("Full Layer Extent"), icon = "fulllayerextent",
851 jonathan 821 sensitive = _has_selected_layer)
852 jonathan 829 _method_command("selected_full_extent", _("&Full selection extent"), "FullSelectionExtent",
853     helptext = _("Full Selection Extent"), icon = "fullselextent",
854     sensitive = _has_selected_shapes)
855 frank 911 _method_command("map_export", _("E&xport"), "ExportMap",
856     helptext = _("Export the map to file"))
857 jan 374 _method_command("map_print", _("Prin&t"), "PrintMap",
858     helptext = _("Print the map"))
859 jonathan 815 _method_command("map_rename", _("&Rename..."), "RenameMap",
860 jonathan 653 helptext = _("Rename the map"))
861 jonathan 815 _method_command("layer_add", _("&Add Layer..."), "AddLayer",
862 jan 374 helptext = _("Add a new layer to active map"))
863 jonathan 937 _method_command("rasterlayer_add", _("&Add Image Layer..."), "AddRasterLayer",
864     helptext = _("Add a new image layer to active map"))
865 jan 374 _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
866     helptext = _("Remove selected layer(s)"),
867 bh 299 sensitive = _can_remove_layer)
868 jonathan 729
869     # Layer menu
870 jonathan 815 _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
871 jonathan 729 sensitive = _has_selected_layer)
872 jan 374 _method_command("layer_raise", _("&Raise"), "RaiseLayer",
873     helptext = _("Raise selected layer(s)"),
874 bh 6 sensitive = _has_selected_layer)
875 jan 374 _method_command("layer_lower", _("&Lower"), "LowerLayer",
876     helptext = _("Lower selected layer(s)"),
877 bh 6 sensitive = _has_selected_layer)
878 jan 374 _method_command("layer_show", _("&Show"), "ShowLayer",
879     helptext = _("Make selected layer(s) visible"),
880 bh 6 sensitive = _has_selected_layer)
881 jan 374 _method_command("layer_hide", _("&Hide"), "HideLayer",
882     helptext = _("Make selected layer(s) unvisible"),
883 bh 6 sensitive = _has_selected_layer)
884 jan 374 _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
885     helptext = _("Show the selected layer's table"),
886 bh 6 sensitive = _has_selected_layer)
887 jonathan 815 _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
888 jonathan 363 sensitive = _has_selected_layer)
889 jonathan 879 _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
890     sensitive = _has_selected_layer)
891     _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
892     sensitive = _has_selected_layer)
893 bh 188
894 jonathan 879 # Table menu
895     _method_command("table_open", _("&Open..."), "TableOpen")
896     _method_command("table_close", _("&Close"), "TableClose")
897     _method_command("table_show", _("&Show"), "TableShow")
898     _method_command("table_hide", _("&Hide"), "TableHide")
899     _method_command("table_join", _("&Join..."), "TableJoin")
900    
901 frank 911 # Export only under Windows ...
902 jonathan 937 map_menu = ["layer_add", "rasterlayer_add", "layer_remove", "map_rename",
903 bh 188 None,
904     "map_projection",
905     None,
906     "map_zoom_in_tool", "map_zoom_out_tool",
907 jonathan 829 "map_pan_tool",
908     "map_full_extent",
909     "layer_full_extent",
910     "selected_full_extent",
911 bh 188 None,
912 jonathan 815 "map_identify_tool", "map_label_tool",
913 bh 188 None,
914 bh 624 "toggle_legend",
915 frank 911 None]
916     if wxPlatform == '__WXMSW__':
917     map_menu.append("map_export")
918     map_menu.append("map_print")
919    
920     # the menu structure
921     main_menu = Menu("<main>", "<main>",
922     [Menu("file", _("&File"),
923     ["new_session", "open_session", None,
924     "save_session", "save_session_as", None,
925     "toggle_session_tree", None,
926     "exit"]),
927     Menu("map", _("&Map"), map_menu),
928 jan 374 Menu("layer", _("&Layer"),
929 jonathan 640 ["layer_raise", "layer_lower",
930 bh 188 None,
931     "layer_show", "layer_hide",
932     None,
933 jonathan 879 "layer_projection",
934     None,
935 jonathan 363 "layer_show_table",
936 jonathan 879 "layer_jointable",
937     "layer_unjointable",
938 jonathan 363 None,
939 jonathan 815 "layer_properties"]),
940 jonathan 879 Menu("table", _("&Table"),
941     ["table_open", "table_close",
942     None,
943     "table_show", "table_hide",
944     None,
945     "table_join"]),
946 jan 374 Menu("help", _("&Help"),
947 bh 188 ["help_about"])])
948 bh 191
949     # the main toolbar
950    
951     main_toolbar = Menu("<toolbar>", "<toolbar>",
952 frank 351 ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
953 jonathan 829 "map_full_extent",
954     "layer_full_extent",
955     "selected_full_extent",
956     None,
957 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