/[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 2363 - (hide annotations)
Fri Oct 1 18:07:14 2004 UTC (20 years, 5 months ago) by joey
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 49266 byte(s)
The map can be retrieved through the parent which is passed to the
constructor anyway and doesn't require an argument of its own,
required for the unification of arguments for general use through
properties-dialog selector.

1 bh 2061 # Copyright (C) 2001, 2002, 2003, 2004 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 bh 1644 # $Source$
16     # $Id$
17 bh 6
18 bh 188 import os
19 bh 1094 import copy
20 bh 6
21     from wxPython.wx import *
22    
23     import Thuban
24 frank 923
25 jan 374 from Thuban import _
26 bh 1782 from Thuban.Model.messages import TITLE_CHANGED
27 bh 188 from Thuban.Model.session import create_empty_session
28 jonathan 937 from Thuban.Model.layer import Layer, RasterLayer
29 bh 1625 from Thuban.Model.postgisdb import PostGISShapeStore, has_postgis_support
30 jan 1155 # XXX: replace this by
31     # from wxPython.lib.dialogs import wxMultipleChoiceDialog
32     # when Thuban does not support wxPython 2.4.0 any more.
33     from Thuban.UI.multiplechoicedialog import wxMultipleChoiceDialog
34    
35 bh 6 import view
36     import tree
37     import tableview, identifyview
38 jonathan 633 from Thuban.UI.classifier import Classifier
39 jonathan 550 import legend
40 bh 188 from menu import Menu
41 bh 6
42 bh 222 from context import Context
43 bh 357 from command import registry, Command, ToolCommand
44 bh 1464 from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION, \
45     MAP_REPLACED
46 jonathan 1309 from about import About
47 bh 6
48 bh 704 from Thuban.UI.dock import DockFrame
49 jonathan 879 from Thuban.UI.join import JoinDialog
50 bh 1648 from Thuban.UI.dbdialog import DBFrame, DBDialog, ChooseDBTableDialog
51 jonathan 653 import resource
52 jonathan 1164 import Thuban.Model.resource
53 jonathan 563
54 jonathan 713 import projdialog
55 jonathan 653
56 jonathan 1309
57 jonathan 573 class MainWindow(DockFrame):
58 bh 6
59 bh 535 # Some messages that can be subscribed/unsubscribed directly through
60     # the MapCanvas come in fact from other objects. This is a map to
61     # map those messages to the names of the instance variables they
62     # actually come from. This delegation is implemented in the
63     # Subscribe and unsubscribed methods
64     delegated_messages = {LAYER_SELECTED: "canvas",
65 bh 1464 SHAPES_SELECTED: "canvas",
66     MAP_REPLACED: "canvas"}
67 bh 535
68     # Methods delegated to some instance variables. The delegation is
69     # implemented in the __getattr__ method.
70     delegated_methods = {"SelectLayer": "canvas",
71     "SelectShapes": "canvas",
72 bh 1074 "SelectedLayer": "canvas",
73 jonathan 879 "SelectedShapes": "canvas",
74 bh 535 }
75    
76 bh 235 def __init__(self, parent, ID, title, application, interactor,
77 bh 238 initial_message = None, size = wxSize(-1, -1)):
78 jonathan 573 DockFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
79     #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
80 bh 6
81 bh 227 self.application = application
82 bh 37
83 bh 6 self.CreateStatusBar()
84 bh 235 if initial_message:
85     self.SetStatusText(initial_message)
86 bh 6
87     self.identify_view = None
88    
89     self.init_ids()
90    
91 bh 191 # creat the menubar from the main_menu description
92 bh 188 self.SetMenuBar(self.build_menu_bar(main_menu))
93 bh 6
94 bh 191 # Similarly, create the toolbar from main_toolbar
95     toolbar = self.build_toolbar(main_toolbar)
96 bh 13 # call Realize to make sure that the tools appear.
97     toolbar.Realize()
98 bh 6
99 jonathan 563
100 bh 6 # Create the map canvas
101 bh 535 canvas = view.MapCanvas(self, -1)
102 bh 123 canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
103 bh 535 canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
104 bh 6 self.canvas = canvas
105 bh 1782 self.canvas.Subscribe(TITLE_CHANGED, self.title_changed)
106 bh 6
107 jonathan 573 self.SetMainWindow(self.canvas)
108    
109 jonathan 563 self.SetAutoLayout(True)
110    
111 bh 31 self.init_dialogs()
112    
113 jonathan 1233 self.ShowLegend()
114    
115 frank 951 EVT_CLOSE(self, self.OnClose)
116 bh 6
117 bh 535 def Subscribe(self, channel, *args):
118     """Subscribe a function to a message channel.
119    
120     If channel is one of the delegated messages call the appropriate
121     object's Subscribe method. Otherwise do nothing.
122     """
123     if channel in self.delegated_messages:
124     object = getattr(self, self.delegated_messages[channel])
125     object.Subscribe(channel, *args)
126     else:
127     print "Trying to subscribe to unsupported channel %s" % channel
128    
129     def Unsubscribe(self, channel, *args):
130     """Unsubscribe a function from a message channel.
131    
132     If channel is one of the delegated messages call the appropriate
133     object's Unsubscribe method. Otherwise do nothing.
134     """
135     if channel in self.delegated_messages:
136     object = getattr(self, self.delegated_messages[channel])
137 bh 2017 try:
138     object.Unsubscribe(channel, *args)
139     except wxPyDeadObjectError:
140     # The object was a wxObject and has already been
141     # destroyed. Hopefully it has unsubscribed all its
142     # subscribers already so that it's OK if we do nothing
143     # here
144     pass
145 bh 535
146     def __getattr__(self, attr):
147     """If attr is one of the delegated methods return that method
148    
149     Otherwise raise AttributeError.
150     """
151     if attr in self.delegated_methods:
152     return getattr(getattr(self, self.delegated_methods[attr]), attr)
153     raise AttributeError(attr)
154    
155 bh 6 def init_ids(self):
156     """Initialize the ids"""
157     self.current_id = 6000
158     self.id_to_name = {}
159     self.name_to_id = {}
160 bh 193 self.events_bound = {}
161 bh 6
162     def get_id(self, name):
163     """Return the wxWindows id for the command named name.
164    
165     Create a new one if there isn't one yet"""
166     ID = self.name_to_id.get(name)
167     if ID is None:
168     ID = self.current_id
169     self.current_id = self.current_id + 1
170     self.name_to_id[name] = ID
171     self.id_to_name[ID] = name
172     return ID
173 bh 188
174 bh 193 def bind_command_events(self, command, ID):
175     """Bind the necessary events for the given command and ID"""
176     if not self.events_bound.has_key(ID):
177     # the events haven't been bound yet
178     EVT_MENU(self, ID, self.invoke_command)
179     if command.IsDynamic():
180     EVT_UPDATE_UI(self, ID, self.update_command_ui)
181    
182 bh 188 def build_menu_bar(self, menudesc):
183     """Build and return the menu bar from the menu description"""
184     menu_bar = wxMenuBar()
185    
186     for item in menudesc.items:
187     # here the items must all be Menu instances themselves
188     menu_bar.Append(self.build_menu(item), item.title)
189    
190     return menu_bar
191    
192     def build_menu(self, menudesc):
193 bh 314 """Return a wxMenu built from the menu description menudesc"""
194 bh 188 wxmenu = wxMenu()
195     last = None
196     for item in menudesc.items:
197     if item is None:
198     # a separator. Only add one if the last item was not a
199     # separator
200     if last is not None:
201     wxmenu.AppendSeparator()
202     elif isinstance(item, Menu):
203     # a submenu
204     wxmenu.AppendMenu(wxNewId(), item.title, self.build_menu(item))
205     else:
206     # must the name the name of a command
207     self.add_menu_command(wxmenu, item)
208     last = item
209     return wxmenu
210    
211 bh 191 def build_toolbar(self, toolbardesc):
212     """Build and return the main toolbar window from a toolbar description
213    
214     The parameter should be an instance of the Menu class but it
215     should not contain submenus.
216     """
217     toolbar = self.CreateToolBar(wxTB_3DBUTTONS)
218    
219     # set the size of the tools' bitmaps. Not needed on wxGTK, but
220     # on Windows, although it doesn't work very well there. It seems
221     # that only 16x16 icons are really supported on windows.
222     # We probably shouldn't hardwire the bitmap size here.
223     toolbar.SetToolBitmapSize(wxSize(24, 24))
224    
225     for item in toolbardesc.items:
226     if item is None:
227     toolbar.AddSeparator()
228     else:
229     # assume it's a string.
230     self.add_toolbar_command(toolbar, item)
231    
232     return toolbar
233    
234 bh 6 def add_menu_command(self, menu, name):
235     """Add the command with name name to the menu menu.
236    
237     If name is None, add a separator.
238     """
239     if name is None:
240     menu.AppendSeparator()
241     else:
242     command = registry.Command(name)
243     if command is not None:
244     ID = self.get_id(name)
245     menu.Append(ID, command.Title(), command.HelpText(),
246     command.IsCheckCommand())
247 bh 193 self.bind_command_events(command, ID)
248 bh 6 else:
249 jan 374 print _("Unknown command %s") % name
250 bh 6
251     def add_toolbar_command(self, toolbar, name):
252     """Add the command with name name to the toolbar toolbar.
253    
254     If name is None, add a separator.
255     """
256     # Assume that all toolbar commands are also menu commmands so
257     # that we don't have to add the event handlers here
258     if name is None:
259     toolbar.AddSeparator()
260     else:
261     command = registry.Command(name)
262     if command is not None:
263     ID = self.get_id(name)
264 jonathan 653 bitmap = resource.GetBitmapResource(command.Icon(),
265     wxBITMAP_TYPE_XPM)
266 bh 6 toolbar.AddTool(ID, bitmap,
267     shortHelpString = command.HelpText(),
268     isToggle = command.IsCheckCommand())
269 bh 193 self.bind_command_events(command, ID)
270 bh 6 else:
271 jan 374 print _("Unknown command %s") % name
272 bh 6
273 bh 281 def Context(self):
274     """Return the context object for a command invoked from this window
275     """
276     return Context(self.application, self.application.Session(), self)
277    
278 bh 6 def invoke_command(self, event):
279     name = self.id_to_name.get(event.GetId())
280     if name is not None:
281     command = registry.Command(name)
282 bh 281 command.Execute(self.Context())
283 bh 6 else:
284 jan 374 print _("Unknown command ID %d") % event.GetId()
285 bh 6
286     def update_command_ui(self, event):
287     #print "update_command_ui", self.id_to_name[event.GetId()]
288 bh 281 context = self.Context()
289 bh 6 command = registry.Command(self.id_to_name[event.GetId()])
290     if command is not None:
291 bh 357 sensitive = command.Sensitive(context)
292     event.Enable(sensitive)
293     if command.IsTool() and not sensitive and command.Checked(context):
294     # When a checked tool command is disabled deselect all
295     # tools. Otherwise the tool would remain active but it
296     # might lead to errors if the tools stays active. This
297     # problem occurred in GREAT-ER and this fixes it, but
298     # it's not clear to me whether this is really the best
299     # way to do it (BH, 20021206).
300     self.canvas.SelectTool(None)
301 bh 222 event.SetText(command.DynText(context))
302 bh 13 if command.IsCheckCommand():
303 bh 357 event.Check(command.Checked(context))
304 bh 6
305 bh 20 def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
306 bh 181 """Run a modal message box with the given text, title and flags
307 bh 20 and return the result"""
308     dlg = wxMessageDialog(self, text, title, flags)
309 bh 316 dlg.CenterOnParent()
310 bh 20 result = dlg.ShowModal()
311     dlg.Destroy()
312     return result
313    
314 bh 31 def init_dialogs(self):
315     """Initialize the dialog handling"""
316     # The mainwindow maintains a dict mapping names to open
317     # non-modal dialogs. The dialogs are put into this dict when
318     # they're created and removed when they're closed
319     self.dialogs = {}
320    
321     def add_dialog(self, name, dialog):
322     if self.dialogs.has_key(name):
323 jan 374 raise RuntimeError(_("The Dialog named %s is already open") % name)
324 bh 31 self.dialogs[name] = dialog
325    
326     def dialog_open(self, name):
327     return self.dialogs.has_key(name)
328    
329     def remove_dialog(self, name):
330     del self.dialogs[name]
331    
332     def get_open_dialog(self, name):
333     return self.dialogs.get(name)
334    
335 bh 123 def view_position_changed(self):
336     pos = self.canvas.CurrentPosition()
337     if pos is not None:
338     text = "(%10.10g, %10.10g)" % pos
339     else:
340     text = ""
341 bh 321 self.set_position_text(text)
342    
343     def set_position_text(self, text):
344     """Set the statusbar text showing the current position.
345    
346     By default the text is shown in field 0 of the status bar.
347     Override this method in derived classes to put it into a
348     different field of the statusbar.
349     """
350 bh 123 self.SetStatusText(text)
351    
352 bh 58 def save_modified_session(self, can_veto = 1):
353     """If the current session has been modified, ask the user
354     whether to save it and do so if requested. Return the outcome of
355     the dialog (either wxID_OK, wxID_CANCEL or wxID_NO). If the
356     dialog wasn't run return wxID_NO.
357    
358     If the can_veto parameter is true (default) the dialog includes
359     a cancel button, otherwise not.
360     """
361 bh 227 if self.application.session.WasModified():
362 bh 58 flags = wxYES_NO | wxICON_QUESTION
363     if can_veto:
364     flags = flags | wxCANCEL
365 jan 374 result = self.RunMessageBox(_("Exit"),
366     _("The session has been modified."
367 bh 58 " Do you want to save it?"),
368     flags)
369     if result == wxID_YES:
370     self.SaveSession()
371     else:
372     result = wxID_NO
373     return result
374    
375 bh 6 def NewSession(self):
376 jonathan 937 if self.save_modified_session() != wxID_CANCEL:
377     self.application.SetSession(create_empty_session())
378 bh 6
379     def OpenSession(self):
380 jonathan 937 if self.save_modified_session() != wxID_CANCEL:
381 frank 2051 dlg = wxFileDialog(self, _("Open Session"),
382     self.application.Path("data"), "",
383 jonathan 937 "Thuban Session File (*.thuban)|*.thuban",
384     wxOPEN)
385     if dlg.ShowModal() == wxID_OK:
386 bh 1648 self.application.OpenSession(dlg.GetPath(),
387     self.run_db_param_dialog)
388 frank 2051 self.application.SetPath("data", dlg.GetPath())
389 jonathan 937 dlg.Destroy()
390 bh 6
391 bh 1648 def run_db_param_dialog(self, parameters, message):
392     dlg = DBDialog(self, _("DB Connection Parameters"), parameters,
393     message)
394     return dlg.RunDialog()
395    
396 bh 6 def SaveSession(self):
397 bh 227 if self.application.session.filename == None:
398 jan 102 self.SaveSessionAs()
399 jonathan 487 else:
400     self.application.SaveSession()
401 bh 6
402     def SaveSessionAs(self):
403 frank 2051 dlg = wxFileDialog(self, _("Save Session As"),
404     self.application.Path("data"), "",
405 jonathan 879 "Thuban Session File (*.thuban)|*.thuban",
406     wxSAVE|wxOVERWRITE_PROMPT)
407 bh 6 if dlg.ShowModal() == wxID_OK:
408 bh 227 self.application.session.SetFilename(dlg.GetPath())
409     self.application.SaveSession()
410 frank 2051 self.application.SetPath("data",dlg.GetPath())
411 bh 6 dlg.Destroy()
412    
413     def Exit(self):
414 jonathan 621 self.Close(False)
415 bh 6
416 frank 951 def OnClose(self, event):
417 bh 58 result = self.save_modified_session(can_veto = event.CanVeto())
418     if result == wxID_CANCEL:
419 bh 6 event.Veto()
420     else:
421 bh 307 # FIXME: it would be better to tie the unsubscription to
422     # wx's destroy event, but that isn't implemented for wxGTK
423     # yet.
424     self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
425 jonathan 974 DockFrame.OnClose(self, event)
426 frank 1056 for dlg in self.dialogs.values():
427     dlg.Destroy()
428     self.canvas.Destroy()
429 bh 6 self.Destroy()
430    
431     def SetMap(self, map):
432     self.canvas.SetMap(map)
433 bh 1782 self.update_title()
434 bh 6
435 jonathan 768 dialog = self.FindRegisteredDock("legend")
436     if dialog is not None:
437     dialog.GetPanel().SetMap(self.Map())
438    
439 bh 310 def Map(self):
440     """Return the map displayed by this mainwindow"""
441 jonathan 563
442 bh 310 return self.canvas.Map()
443    
444 bh 622 def ToggleSessionTree(self):
445     """If the session tree is shown close it otherwise create a new tree"""
446 bh 37 name = "session_tree"
447     dialog = self.get_open_dialog(name)
448     if dialog is None:
449 bh 227 dialog = tree.SessionTreeView(self, self.application, name)
450 bh 37 self.add_dialog(name, dialog)
451 jonathan 512 dialog.Show(True)
452 bh 37 else:
453 bh 622 dialog.Close()
454 bh 37
455 bh 622 def SessionTreeShown(self):
456     """Return true iff the session tree is currently shown"""
457     return self.get_open_dialog("session_tree") is not None
458 jonathan 517
459 bh 6 def About(self):
460 jonathan 1309 dlg = About(self)
461     dlg.ShowModal()
462     dlg.Destroy()
463 bh 6
464 bh 1620 def DatabaseManagement(self):
465     name = "dbmanagement"
466     dialog = self.get_open_dialog(name)
467     if dialog is None:
468     map = self.canvas.Map()
469     dialog = DBFrame(self, name, self.application.Session())
470     self.add_dialog(name, dialog)
471     dialog.Show()
472     dialog.Raise()
473    
474 bh 6 def AddLayer(self):
475 frank 2051 dlg = wxFileDialog(self, _("Select one or more data files"),
476     self.application.Path("data"), "",
477 bh 1995 _("Shapefiles (*.shp)") + "|*.shp;*.SHP|" +
478     _("All Files (*.*)") + "|*.*",
479 jan 1622 wxOPEN | wxMULTIPLE)
480 bh 6 if dlg.ShowModal() == wxID_OK:
481 jan 1622 filenames = dlg.GetPaths()
482     for filename in filenames:
483     title = os.path.splitext(os.path.basename(filename))[0]
484     map = self.canvas.Map()
485     has_layers = map.HasLayers()
486     try:
487     store = self.application.Session().OpenShapefile(filename)
488     except IOError:
489     # the layer couldn't be opened
490     self.RunMessageBox(_("Add Layer"),
491     _("Can't open the file '%s'.")%filename)
492     else:
493     layer = Layer(title, store)
494     map.AddLayer(layer)
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 frank 2051 self.application.SetPath("data",filename)
500 bh 6 dlg.Destroy()
501    
502 jonathan 937 def AddRasterLayer(self):
503 frank 2051 dlg = wxFileDialog(self, _("Select an image file"),
504     self.application.Path("data"), "", "*.*",
505 jonathan 937 wxOPEN)
506     if dlg.ShowModal() == wxID_OK:
507     filename = dlg.GetPath()
508     title = os.path.splitext(os.path.basename(filename))[0]
509     map = self.canvas.Map()
510     has_layers = map.HasLayers()
511     try:
512 jonathan 963 layer = RasterLayer(title, filename)
513 jonathan 937 except IOError:
514     # the layer couldn't be opened
515     self.RunMessageBox(_("Add Image Layer"),
516     _("Can't open the file '%s'.") % filename)
517     else:
518 jonathan 963 map.AddLayer(layer)
519 jonathan 937 if not has_layers:
520     # if we're adding a layer to an empty map, fit the
521     # new map to the window
522     self.canvas.FitMapToWindow()
523 frank 2051 self.application.SetPath("data", filename)
524 jonathan 937 dlg.Destroy()
525    
526 bh 1620 def AddDBLayer(self):
527     """Add a layer read from a database"""
528     session = self.application.Session()
529 bh 1695 dlg = ChooseDBTableDialog(self, self.application.Session())
530 bh 1620
531     if dlg.ShowModal() == wxID_OK:
532 bh 2102 dbconn, dbtable, id_column, geo_column = dlg.GetTable()
533 bh 1620 try:
534     title = str(dbtable)
535    
536     # Chose the correct Interface for the database type
537 bh 2102 store = session.OpenDBShapeStore(dbconn, dbtable,
538     id_column = id_column,
539     geometry_column = geo_column)
540 bh 1620 layer = Layer(title, store)
541     except:
542     # Some error occured while initializing the layer
543     self.RunMessageBox(_("Add Layer from database"),
544     _("Can't open the database table '%s'")
545     % dbtable)
546 bh 2061 return
547 bh 1620
548     map = self.canvas.Map()
549    
550     has_layers = map.HasLayers()
551     map.AddLayer(layer)
552     if not has_layers:
553     self.canvas.FitMapToWindow()
554    
555     dlg.Destroy()
556    
557 bh 6 def RemoveLayer(self):
558     layer = self.current_layer()
559     if layer is not None:
560     self.canvas.Map().RemoveLayer(layer)
561    
562 bh 299 def CanRemoveLayer(self):
563     """Return true if the currently selected layer can be deleted.
564    
565 jonathan 621 If no layer is selected return False.
566 bh 299
567     The return value of this method determines whether the remove
568     layer command is sensitive in menu.
569     """
570     layer = self.current_layer()
571     if layer is not None:
572     return self.canvas.Map().CanRemoveLayer(layer)
573 jonathan 621 return False
574 bh 299
575 jan 2186 def LayerToTop(self):
576     layer = self.current_layer()
577     if layer is not None:
578     self.canvas.Map().MoveLayerToTop(layer)
579    
580 bh 6 def RaiseLayer(self):
581     layer = self.current_layer()
582     if layer is not None:
583     self.canvas.Map().RaiseLayer(layer)
584 bh 222
585 bh 6 def LowerLayer(self):
586     layer = self.current_layer()
587     if layer is not None:
588     self.canvas.Map().LowerLayer(layer)
589    
590 jan 2186 def LayerToBottom(self):
591     layer = self.current_layer()
592     if layer is not None:
593     self.canvas.Map().MoveLayerToBottom(layer)
594    
595 bh 6 def current_layer(self):
596     """Return the currently selected layer.
597    
598     If no layer is selected, return None
599     """
600 bh 535 return self.canvas.SelectedLayer()
601 bh 6
602     def has_selected_layer(self):
603     """Return true if a layer is currently selected"""
604 bh 535 return self.canvas.HasSelectedLayer()
605 bh 6
606 bh 2019 def has_selected_shape_layer(self):
607     """Return true if a shape layer is currently selected"""
608     return isinstance(self.current_layer(), Layer)
609    
610 jonathan 829 def has_selected_shapes(self):
611     """Return true if a shape is currently selected"""
612     return self.canvas.HasSelectedShapes()
613    
614 bh 6 def HideLayer(self):
615     layer = self.current_layer()
616     if layer is not None:
617 jan 2186 layer.SetVisible(False)
618 bh 1094
619 bh 6 def ShowLayer(self):
620     layer = self.current_layer()
621     if layer is not None:
622 jan 2186 layer.SetVisible(True)
623 bh 6
624 jan 2186 def ToggleLayerVisibility(self):
625     layer = self.current_layer()
626     layer.SetVisible(not layer.Visible())
627    
628 bh 1094 def DuplicateLayer(self):
629     """Ceate a new layer above the selected layer with the same shapestore
630     """
631     layer = self.current_layer()
632     if layer is not None and hasattr(layer, "ShapeStore"):
633     new_layer = Layer(_("Copy of `%s'") % layer.Title(),
634     layer.ShapeStore(),
635     projection = layer.GetProjection())
636     new_classification = copy.deepcopy(layer.GetClassification())
637     new_layer.SetClassification(new_classification)
638     self.Map().AddLayer(new_layer)
639    
640     def CanDuplicateLayer(self):
641     """Return whether the DuplicateLayer method can create a duplicate"""
642     layer = self.current_layer()
643     return layer is not None and hasattr(layer, "ShapeStore")
644    
645 bh 6 def LayerShowTable(self):
646 jan 2184 """
647     Present a TableView Window for the current layer.
648     In case the window is already open, bring it to the front.
649     In case, there is no active layer, do nothing.
650 jan 2186 In case, the layer has no ShapeStore, do nothing.
651 jan 2184 """
652 bh 6 layer = self.current_layer()
653     if layer is not None:
654 jan 2184 if not hasattr(layer, "ShapeStore"):
655     return
656 bh 1219 table = layer.ShapeStore().Table()
657 bh 31 name = "table_view" + str(id(table))
658     dialog = self.get_open_dialog(name)
659     if dialog is None:
660 bh 535 dialog = tableview.LayerTableFrame(self, name,
661 jan 1023 _("Layer Table: %s") % layer.Title(),
662     layer, table)
663 bh 31 self.add_dialog(name, dialog)
664 jan 1035 dialog.Show(True)
665 bh 31 else:
666 joey 2163 dialog.Raise()
667 bh 6
668 jonathan 729 def MapProjection(self):
669 bh 6
670 jonathan 729 name = "map_projection"
671 jonathan 713 dialog = self.get_open_dialog(name)
672    
673     if dialog is None:
674     map = self.canvas.Map()
675 jonathan 750 dialog = projdialog.ProjFrame(self, name,
676     _("Map Projection: %s") % map.Title(), map)
677 jonathan 713 self.add_dialog(name, dialog)
678     dialog.Show()
679     dialog.Raise()
680    
681 jonathan 729 def LayerProjection(self):
682    
683     layer = self.current_layer()
684    
685     name = "layer_projection" + str(id(layer))
686     dialog = self.get_open_dialog(name)
687    
688     if dialog is None:
689     map = self.canvas.Map()
690 jonathan 750 dialog = projdialog.ProjFrame(self, name,
691     _("Layer Projection: %s") % layer.Title(), layer)
692 jonathan 729 self.add_dialog(name, dialog)
693     dialog.Show()
694     dialog.Raise()
695    
696 jonathan 640 def LayerEditProperties(self):
697 jonathan 363
698 jonathan 487 #
699     # the menu option for this should only be available if there
700     # is a current layer, so we don't need to check if the
701     # current layer is None
702     #
703    
704     layer = self.current_layer()
705 jonathan 640 self.OpenLayerProperties(layer)
706 jonathan 550
707 jonathan 640 def OpenLayerProperties(self, layer, group = None):
708     name = "layer_properties" + str(id(layer))
709 jonathan 487 dialog = self.get_open_dialog(name)
710    
711     if dialog is None:
712 joey 2363 dialog = Classifier(self, name, layer, group)
713 jonathan 487 self.add_dialog(name, dialog)
714     dialog.Show()
715 jonathan 573 dialog.Raise()
716 jonathan 487
717 jonathan 879 def LayerJoinTable(self):
718 bh 1072 layer = self.canvas.SelectedLayer()
719     if layer is not None:
720     dlg = JoinDialog(self, _("Join Layer with Table"),
721     self.application.session,
722     layer = layer)
723     dlg.ShowModal()
724 jonathan 550
725 jonathan 879 def LayerUnjoinTable(self):
726 bh 1074 layer = self.canvas.SelectedLayer()
727     if layer is not None:
728     orig_store = layer.ShapeStore().OrigShapeStore()
729     if orig_store:
730     layer.SetShapeStore(orig_store)
731 jonathan 879
732 jonathan 621 def ShowLegend(self):
733 bh 622 if not self.LegendShown():
734     self.ToggleLegend()
735    
736     def ToggleLegend(self):
737     """Show the legend if it's not shown otherwise hide it again"""
738 jonathan 550 name = "legend"
739 jonathan 573 dialog = self.FindRegisteredDock(name)
740 jonathan 550
741     if dialog is None:
742 jonathan 640 dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
743 jonathan 573 legend.LegendPanel(dialog, None, self)
744 jonathan 580 dialog.Dock()
745 bh 622 dialog.GetPanel().SetMap(self.Map())
746     dialog.Show()
747     else:
748     dialog.Show(not dialog.IsShown())
749 jonathan 563
750 bh 622 def LegendShown(self):
751     """Return true iff the legend is currently open"""
752     dialog = self.FindRegisteredDock("legend")
753     return dialog is not None and dialog.IsShown()
754 jonathan 563
755 jonathan 879 def TableOpen(self):
756 frank 2051 dlg = wxFileDialog(self, _("Open Table"),
757     self.application.Path("data"), "",
758 bh 1037 _("DBF Files (*.dbf)") + "|*.dbf|" +
759     #_("CSV Files (*.csv)") + "|*.csv|" +
760     _("All Files (*.*)") + "|*.*",
761 jonathan 879 wxOPEN)
762     if dlg.ShowModal() == wxID_OK:
763 bh 1054 filename = dlg.GetPath()
764     dlg.Destroy()
765     try:
766     table = self.application.session.OpenTableFile(filename)
767     except IOError:
768     # the layer couldn't be opened
769     self.RunMessageBox(_("Open Table"),
770     _("Can't open the file '%s'.") % filename)
771     else:
772     self.ShowTableView(table)
773 frank 2051 self.application.SetPath("data",filename)
774 jonathan 879
775     def TableClose(self):
776 bh 1068 tables = self.application.session.UnreferencedTables()
777 jonathan 879
778 jan 1084 lst = [(t.Title(), t) for t in tables]
779     lst.sort()
780     titles = [i[0] for i in lst]
781 bh 1068 dlg = wxMultipleChoiceDialog(self, _("Pick the tables to close:"),
782 jan 1084 _("Close Table"), titles,
783     size = (400, 300),
784     style = wxDEFAULT_DIALOG_STYLE |
785     wxRESIZE_BORDER)
786 bh 1068 if dlg.ShowModal() == wxID_OK:
787     for i in dlg.GetValue():
788 jan 1084 self.application.session.RemoveTable(lst[i][1])
789 bh 1068
790    
791 jonathan 879 def TableShow(self):
792 jan 1014 """Offer a multi-selection dialog for tables to be displayed
793 bh 1054
794 jan 1014 The windows for the selected tables are opened or brought to
795     the front.
796     """
797     tables = self.application.session.Tables()
798 jonathan 879
799 jan 1084 lst = [(t.Title(), t) for t in tables]
800     lst.sort()
801     titles = [i[0] for i in lst]
802 jan 1014 dlg = wxMultipleChoiceDialog(self, _("Pick the table to show:"),
803 jan 1084 _("Show Table"), titles,
804 frank 1076 size = (400,300),
805     style = wxDEFAULT_DIALOG_STYLE |
806     wxRESIZE_BORDER)
807 jan 1014 if (dlg.ShowModal() == wxID_OK):
808     for i in dlg.GetValue():
809 jan 1023 # XXX: if the table belongs to a layer, open a
810     # LayerTableFrame instead of QueryTableFrame
811 jan 1084 self.ShowTableView(lst[i][1])
812 jan 1014
813 jonathan 879 def TableJoin(self):
814     dlg = JoinDialog(self, _("Join Tables"), self.application.session)
815 frank 1001 dlg.ShowModal()
816 jonathan 879
817 bh 1054 def ShowTableView(self, table):
818     """Open a table view for the table and optionally"""
819     name = "table_view%d" % id(table)
820     dialog = self.get_open_dialog(name)
821     if dialog is None:
822     dialog = tableview.QueryTableFrame(self, name,
823     _("Table: %s") % table.Title(),
824     table)
825     self.add_dialog(name, dialog)
826     dialog.Show(True)
827 jonathan 1393 dialog.Raise()
828 bh 1054
829 bh 1126 def TableRename(self):
830     """Let the user rename a table"""
831    
832     # First, let the user select a table
833     tables = self.application.session.Tables()
834     lst = [(t.Title(), t) for t in tables]
835     lst.sort()
836     titles = [i[0] for i in lst]
837     dlg = wxMultipleChoiceDialog(self, _("Pick the table to rename:"),
838     _("Rename Table"), titles,
839     size = (400,300),
840     style = wxDEFAULT_DIALOG_STYLE |
841     wxRESIZE_BORDER)
842     if (dlg.ShowModal() == wxID_OK):
843     to_rename = [lst[i][1] for i in dlg.GetValue()]
844     dlg.Destroy()
845     else:
846     to_rename = []
847    
848     # Second, let the user rename the layers
849     for table in to_rename:
850 bh 2040 dlg = wxTextEntryDialog(self, _("Table Title:"), _("Rename Table"),
851 bh 1126 table.Title())
852     try:
853     if dlg.ShowModal() == wxID_OK:
854     title = dlg.GetValue()
855     if title != "":
856     table.SetTitle(title)
857    
858     # Make sure the session is marked as modified.
859     # FIXME: This should be handled automatically,
860     # but that requires more changes to the tables
861     # than I have time for currently.
862     self.application.session.changed()
863     finally:
864     dlg.Destroy()
865    
866    
867 bh 6 def ZoomInTool(self):
868     self.canvas.ZoomInTool()
869    
870     def ZoomOutTool(self):
871     self.canvas.ZoomOutTool()
872    
873     def PanTool(self):
874     self.canvas.PanTool()
875    
876     def IdentifyTool(self):
877     self.canvas.IdentifyTool()
878 bh 49 self.identify_view_on_demand(None, None)
879 bh 6
880     def LabelTool(self):
881     self.canvas.LabelTool()
882    
883     def FullExtent(self):
884     self.canvas.FitMapToWindow()
885    
886 jonathan 821 def FullLayerExtent(self):
887     self.canvas.FitLayerToWindow(self.current_layer())
888    
889 jonathan 829 def FullSelectionExtent(self):
890     self.canvas.FitSelectedToWindow()
891    
892 frank 911 def ExportMap(self):
893     self.canvas.Export()
894    
895 bh 6 def PrintMap(self):
896     self.canvas.Print()
897    
898 jonathan 653 def RenameMap(self):
899 bh 2040 dlg = wxTextEntryDialog(self, _("Map Title:"), _("Rename Map"),
900 jonathan 653 self.Map().Title())
901     if dlg.ShowModal() == wxID_OK:
902     title = dlg.GetValue()
903     if title != "":
904     self.Map().SetTitle(title)
905    
906     dlg.Destroy()
907    
908 bh 1126 def RenameLayer(self):
909     """Let the user rename the currently selected layer"""
910     layer = self.current_layer()
911     if layer is not None:
912 bh 2040 dlg = wxTextEntryDialog(self, _("Layer Title:"), _("Rename Layer"),
913 bh 1126 layer.Title())
914     try:
915     if dlg.ShowModal() == wxID_OK:
916     title = dlg.GetValue()
917     if title != "":
918     layer.SetTitle(title)
919     finally:
920     dlg.Destroy()
921    
922 bh 535 def identify_view_on_demand(self, layer, shapes):
923 bh 787 """Subscribed to the canvas' SHAPES_SELECTED message
924    
925     If the current tool is the identify tool, at least one shape is
926     selected and the identify dialog is not shown, show the dialog.
927     """
928     # If the selection has become empty we don't need to do
929     # anything. Otherwise it could happen that the dialog was popped
930     # up when the selection became empty, e.g. when a new selection
931     # is opened while the identify tool is active and dialog had
932     # been closed
933     if not shapes:
934     return
935    
936 bh 31 name = "identify_view"
937     if self.canvas.CurrentTool() == "IdentifyTool":
938     if not self.dialog_open(name):
939 bh 535 dialog = identifyview.IdentifyView(self, name)
940 bh 31 self.add_dialog(name, dialog)
941 jonathan 563 dialog.Show(True)
942 bh 31 else:
943 bh 33 # FIXME: bring dialog to front?
944 bh 31 pass
945 bh 6
946 bh 1782 def title_changed(self, map):
947     """Subscribed to the canvas' TITLE_CHANGED messages"""
948     self.update_title()
949 jonathan 653
950 bh 1782 def update_title(self):
951     """Update the window's title according to it's current state.
952    
953     In this default implementation the title is 'Thuban - ' followed
954     by the map's title or simply 'Thuban' if there is not map.
955     Derived classes should override this method to get different
956     titles.
957    
958     This method is called automatically by other methods when the
959     title may have to change. For the methods implemented in this
960     class this usually only means that a different map has been set
961     or the current map's title has changed.
962     """
963     map = self.Map()
964     if map is not None:
965     title = _("Thuban - %s") % (map.Title(),)
966     else:
967     title = _("Thuban")
968     self.SetTitle(title)
969    
970    
971 bh 6 #
972     # Define all the commands available in the main window
973     #
974    
975    
976     # Helper functions to define common command implementations
977     def call_method(context, methodname, *args):
978 bh 222 """Call the mainwindow's method methodname with args *args"""
979     apply(getattr(context.mainwindow, methodname), args)
980 bh 6
981 jan 110 def _method_command(name, title, method, helptext = "",
982 bh 622 icon = "", sensitive = None, checked = None):
983 bh 222 """Add a command implemented by a method of the mainwindow object"""
984 bh 6 registry.Add(Command(name, title, call_method, args=(method,),
985 jan 110 helptext = helptext, icon = icon,
986 bh 622 sensitive = sensitive, checked = checked))
987 jan 110
988 bh 270 def make_check_current_tool(toolname):
989     """Return a function that tests if the currently active tool is toolname
990    
991     The returned function can be called with the context and returns
992     true iff the currently active tool's name is toolname. It's directly
993     usable as the 'checked' callback of a command.
994     """
995     def check_current_tool(context, name=toolname):
996     return context.mainwindow.canvas.CurrentTool() == name
997     return check_current_tool
998    
999 bh 6 def _tool_command(name, title, method, toolname, helptext = "",
1000 bh 310 icon = "", sensitive = None):
1001 bh 6 """Add a tool command"""
1002 bh 357 registry.Add(ToolCommand(name, title, call_method, args=(method,),
1003     helptext = helptext, icon = icon,
1004     checked = make_check_current_tool(toolname),
1005     sensitive = sensitive))
1006 bh 6
1007     def _has_selected_layer(context):
1008     """Return true if a layer is selected in the context"""
1009 bh 222 return context.mainwindow.has_selected_layer()
1010 bh 6
1011 jan 2186 def _has_selected_layer_visible(context):
1012     """Return true if a layer is selected in the context which is
1013     visible."""
1014     if context.mainwindow.has_selected_layer():
1015     layer = context.mainwindow.current_layer()
1016     if layer.Visible(): return True
1017     return False
1018    
1019 bh 2019 def _has_selected_shape_layer(context):
1020     """Return true if a shape layer is selected in the context"""
1021     return context.mainwindow.has_selected_shape_layer()
1022    
1023 jonathan 829 def _has_selected_shapes(context):
1024     """Return true if a layer is selected in the context"""
1025     return context.mainwindow.has_selected_shapes()
1026    
1027 bh 299 def _can_remove_layer(context):
1028     return context.mainwindow.CanRemoveLayer()
1029    
1030 jan 264 def _has_tree_window_shown(context):
1031     """Return true if the tree window is shown"""
1032 bh 622 return context.mainwindow.SessionTreeShown()
1033 jan 264
1034 bh 310 def _has_visible_map(context):
1035     """Return true iff theres a visible map in the mainwindow.
1036    
1037     A visible map is a map with at least one visible layer."""
1038     map = context.mainwindow.Map()
1039     if map is not None:
1040     for layer in map.Layers():
1041     if layer.Visible():
1042 jan 2186 return True
1043     return False
1044 bh 310
1045 jonathan 550 def _has_legend_shown(context):
1046     """Return true if the legend window is shown"""
1047 bh 622 return context.mainwindow.LegendShown()
1048 bh 310
1049 jonathan 1164 def _has_gdal_support(context):
1050     """Return True if the GDAL is available"""
1051     return Thuban.Model.resource.has_gdal_support()
1052 jonathan 550
1053 bh 1620 def _has_dbconnections(context):
1054     """Return whether the the session has database connections"""
1055     return context.session.HasDBConnections()
1056    
1057 bh 1625 def _has_postgis_support(context):
1058     return has_postgis_support()
1059    
1060    
1061 bh 6 # File menu
1062 jan 1140 _method_command("new_session", _("&New Session"), "NewSession",
1063     helptext = _("Start a new session"))
1064     _method_command("open_session", _("&Open Session..."), "OpenSession",
1065     helptext = _("Open a session file"))
1066     _method_command("save_session", _("&Save Session"), "SaveSession",
1067     helptext =_("Save this session to the file it was opened from"))
1068     _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs",
1069     helptext = _("Save this session to a new file"))
1070 bh 622 _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
1071 jan 1140 checked = _has_tree_window_shown,
1072     helptext = _("Toggle on/off the session tree analysis window"))
1073 bh 622 _method_command("toggle_legend", _("Legend"), "ToggleLegend",
1074 jan 1140 checked = _has_legend_shown,
1075     helptext = _("Toggle Legend on/off"))
1076 bh 1620 _method_command("database_management", _("&Database Connections..."),
1077 bh 1625 "DatabaseManagement",
1078     sensitive = _has_postgis_support)
1079 jan 1140 _method_command("exit", _("E&xit"), "Exit",
1080     helptext = _("Finish working with Thuban"))
1081 bh 6
1082     # Help menu
1083 jan 1140 _method_command("help_about", _("&About..."), "About",
1084     helptext = _("Info about Thuban authors, version and modules"))
1085 bh 6
1086    
1087     # Map menu
1088 jan 1140 _method_command("map_projection", _("Pro&jection..."), "MapProjection",
1089     helptext = _("Set or change the map projection"))
1090 bh 6
1091 jan 374 _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
1092     helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
1093 bh 310 sensitive = _has_visible_map)
1094 jan 374 _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
1095     helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
1096 bh 310 sensitive = _has_visible_map)
1097 jan 374 _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
1098     helptext = _("Switch to map-mode 'pan'"), icon = "pan",
1099 bh 310 sensitive = _has_visible_map)
1100 jan 374 _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
1101     "IdentifyTool",
1102     helptext = _("Switch to map-mode 'identify'"), icon = "identify",
1103 bh 310 sensitive = _has_visible_map)
1104 jan 374 _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
1105     helptext = _("Add/Remove labels"), icon = "label",
1106 bh 310 sensitive = _has_visible_map)
1107 jan 374 _method_command("map_full_extent", _("&Full extent"), "FullExtent",
1108 jan 1140 helptext = _("Zoom to the full map extent"), icon = "fullextent",
1109 bh 310 sensitive = _has_visible_map)
1110 jonathan 821 _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
1111 jan 1140 helptext = _("Zoom to the full layer extent"),
1112     icon = "fulllayerextent", sensitive = _has_selected_layer)
1113     _method_command("selected_full_extent", _("&Full selection extent"),
1114     "FullSelectionExtent",
1115     helptext = _("Zoom to the full selection extent"),
1116     icon = "fullselextent", sensitive = _has_selected_shapes)
1117 frank 911 _method_command("map_export", _("E&xport"), "ExportMap",
1118 jan 1140 helptext = _("Export the map to file"))
1119 jan 374 _method_command("map_print", _("Prin&t"), "PrintMap",
1120     helptext = _("Print the map"))
1121 jonathan 815 _method_command("map_rename", _("&Rename..."), "RenameMap",
1122 jonathan 653 helptext = _("Rename the map"))
1123 jonathan 815 _method_command("layer_add", _("&Add Layer..."), "AddLayer",
1124 jan 1140 helptext = _("Add a new layer to the map"))
1125 jonathan 937 _method_command("rasterlayer_add", _("&Add Image Layer..."), "AddRasterLayer",
1126 jonathan 1164 helptext = _("Add a new image layer to the map"),
1127     sensitive = _has_gdal_support)
1128 bh 1620 _method_command("layer_add_db", _("Add &Database Layer..."), "AddDBLayer",
1129     helptext = _("Add a new database layer to active map"),
1130     sensitive = _has_dbconnections)
1131 jan 374 _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
1132 jan 1140 helptext = _("Remove selected layer"),
1133 bh 299 sensitive = _can_remove_layer)
1134 jonathan 729
1135     # Layer menu
1136 jonathan 815 _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
1137 jan 1140 sensitive = _has_selected_layer,
1138     helptext = _("Specify projection for selected layer"))
1139 bh 1094 _method_command("layer_duplicate", _("&Duplicate"), "DuplicateLayer",
1140 jan 1140 helptext = _("Duplicate selected layer"),
1141 bh 1094 sensitive = lambda context: context.mainwindow.CanDuplicateLayer())
1142 bh 1126 _method_command("layer_rename", _("Re&name ..."), "RenameLayer",
1143     helptext = _("Rename selected layer"),
1144     sensitive = _has_selected_layer)
1145 jan 374 _method_command("layer_raise", _("&Raise"), "RaiseLayer",
1146 jan 1140 helptext = _("Raise selected layer"),
1147 bh 6 sensitive = _has_selected_layer)
1148 jan 374 _method_command("layer_lower", _("&Lower"), "LowerLayer",
1149 jan 1140 helptext = _("Lower selected layer"),
1150 bh 6 sensitive = _has_selected_layer)
1151 jan 374 _method_command("layer_show", _("&Show"), "ShowLayer",
1152 jan 1140 helptext = _("Make selected layer visible"),
1153 bh 6 sensitive = _has_selected_layer)
1154 jan 374 _method_command("layer_hide", _("&Hide"), "HideLayer",
1155 jan 1140 helptext = _("Make selected layer unvisible"),
1156 bh 6 sensitive = _has_selected_layer)
1157 jan 374 _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
1158     helptext = _("Show the selected layer's table"),
1159 bh 2019 sensitive = _has_selected_shape_layer)
1160 jonathan 815 _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
1161 jan 1140 sensitive = _has_selected_layer,
1162     helptext = _("Edit the properties of the selected layer"))
1163 jonathan 879 _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
1164 bh 2019 sensitive = _has_selected_shape_layer,
1165 jan 1140 helptext = _("Join and attach a table to the selected layer"))
1166 bh 1074
1167 jan 2186 # further layer methods:
1168     _method_command("layer_to_top", _("&Top"), "LayerToTop",
1169     helptext = _("Put selected layer to the top"),
1170     sensitive = _has_selected_layer)
1171     _method_command("layer_to_bottom", _("&Bottom"), "LayerToBottom",
1172     helptext = _("Put selected layer to the bottom"),
1173     sensitive = _has_selected_layer)
1174     _method_command("layer_visibility", _("&Visible"), "ToggleLayerVisibility",
1175     checked = _has_selected_layer_visible,
1176     helptext = _("Toggle visibility of selected layer"),
1177     sensitive = _has_selected_layer)
1178    
1179 bh 1074 def _can_unjoin(context):
1180 bh 1080 """Return whether the Layer/Unjoin command can be executed.
1181    
1182     This is the case if a layer is selected and that layer has a
1183     shapestore that has an original shapestore.
1184     """
1185 bh 1074 layer = context.mainwindow.SelectedLayer()
1186 bh 1080 if layer is None:
1187     return 0
1188     getstore = getattr(layer, "ShapeStore", None)
1189     if getstore is not None:
1190     return getstore().OrigShapeStore() is not None
1191     else:
1192     return 0
1193 jonathan 879 _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
1194 jan 1140 sensitive = _can_unjoin,
1195     helptext = _("Undo the last join operation"))
1196 bh 188
1197 bh 1126
1198     def _has_tables(context):
1199     return bool(context.session.Tables())
1200    
1201 jonathan 879 # Table menu
1202 jan 1140 _method_command("table_open", _("&Open..."), "TableOpen",
1203     helptext = _("Open a DBF-table from a file"))
1204     _method_command("table_close", _("&Close..."), "TableClose",
1205     sensitive = lambda context: bool(context.session.UnreferencedTables()),
1206     helptext = _("Close one or more tables from a list"))
1207 bh 1126 _method_command("table_rename", _("&Rename..."), "TableRename",
1208 jan 1140 sensitive = _has_tables,
1209     helptext = _("Rename one or more tables"))
1210     _method_command("table_show", _("&Show..."), "TableShow",
1211     sensitive = _has_tables,
1212     helptext = _("Show one or more tables in a dialog"))
1213 bh 1126 _method_command("table_join", _("&Join..."), "TableJoin",
1214 jan 1140 sensitive = _has_tables,
1215     helptext = _("Join two tables creating a new one"))
1216 jonathan 879
1217 frank 911 # Export only under Windows ...
1218 bh 1620 map_menu = ["layer_add", "layer_add_db", "rasterlayer_add", "layer_remove",
1219 bh 188 None,
1220 jonathan 1164 "map_rename",
1221 bh 188 "map_projection",
1222     None,
1223     "map_zoom_in_tool", "map_zoom_out_tool",
1224 bh 1620 "map_pan_tool",
1225     "map_full_extent",
1226 jonathan 829 "layer_full_extent",
1227     "selected_full_extent",
1228 bh 188 None,
1229 jonathan 815 "map_identify_tool", "map_label_tool",
1230 bh 188 None,
1231 bh 624 "toggle_legend",
1232 frank 911 None]
1233     if wxPlatform == '__WXMSW__':
1234     map_menu.append("map_export")
1235     map_menu.append("map_print")
1236    
1237     # the menu structure
1238     main_menu = Menu("<main>", "<main>",
1239     [Menu("file", _("&File"),
1240     ["new_session", "open_session", None,
1241     "save_session", "save_session_as", None,
1242 bh 1620 "database_management", None,
1243 frank 911 "toggle_session_tree", None,
1244     "exit"]),
1245     Menu("map", _("&Map"), map_menu),
1246 jan 374 Menu("layer", _("&Layer"),
1247 bh 1126 ["layer_rename", "layer_duplicate",
1248 bh 188 None,
1249 bh 1126 "layer_raise", "layer_lower",
1250     None,
1251 bh 188 "layer_show", "layer_hide",
1252     None,
1253 jonathan 879 "layer_projection",
1254     None,
1255 jonathan 363 "layer_show_table",
1256 jonathan 879 "layer_jointable",
1257     "layer_unjointable",
1258 jonathan 363 None,
1259 jonathan 815 "layer_properties"]),
1260 jonathan 879 Menu("table", _("&Table"),
1261 bh 1126 ["table_open", "table_close", "table_rename",
1262 jonathan 879 None,
1263 bh 1052 "table_show",
1264 jonathan 879 None,
1265     "table_join"]),
1266 jan 374 Menu("help", _("&Help"),
1267 bh 188 ["help_about"])])
1268 bh 191
1269     # the main toolbar
1270    
1271     main_toolbar = Menu("<toolbar>", "<toolbar>",
1272 frank 351 ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
1273 jonathan 829 "map_full_extent",
1274     "layer_full_extent",
1275     "selected_full_extent",
1276     None,
1277 frank 351 "map_identify_tool", "map_label_tool"])
1278 jonathan 1293

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26