/[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 2520 - (hide annotations)
Tue Jan 11 16:52:40 2005 UTC (20 years, 2 months ago) by frank
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 50178 byte(s)
* Thuban/UI/mainwindow.py (MainWindow.DuplicateLayer):
	Fix indention bug.

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