/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/mainwindow.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/mainwindow.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 270 by bh, Thu Aug 22 13:46:46 2002 UTC revision 1233 by jonathan, Wed Jun 18 14:47:19 2003 UTC
# Line 1  Line 1 
1  # Copyright (C) 2001, 2002 by Intevation GmbH  # Copyright (C) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jan-Oliver Wagner <[email protected]>  # Jan-Oliver Wagner <[email protected]>
4  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
5    # Frank Koormann <[email protected]>
6  #  #
7  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
8  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
# Line 12  The main window Line 13  The main window
13    
14  __version__ = "$Revision$"  __version__ = "$Revision$"
15    
16    __ThubanVersion__ = "0.2" #"$THUBAN_0_2$"
17    #__BuildDate__ = "$Date$"
18    
19  import os  import os
20    import copy
21    
22  from wxPython.wx import *  from wxPython.wx import *
23    from wxPython.wx import __version__ as wxPython_version
24    
25  import Thuban  import Thuban
26    import Thuban.version
27    
28    from Thuban import _
29  from Thuban.Model.session import create_empty_session  from Thuban.Model.session import create_empty_session
30  from Thuban.Model.layer import Layer  from Thuban.Model.layer import Layer, RasterLayer
31  from Thuban.Model.color import Color  
32  from Thuban.Model.proj import Projection  # XXX: replace this by
33    # from wxPython.lib.dialogs import wxMultipleChoiceDialog
34    # when Thuban does not support wxPython 2.4.0 any more.
35    from Thuban.UI.multiplechoicedialog import wxMultipleChoiceDialog
36    
37  import view  import view
38  import tree  import tree
 import proj4dialog  
39  import tableview, identifyview  import tableview, identifyview
40    from Thuban.UI.classifier import Classifier
41    import legend
42  from menu import Menu  from menu import Menu
43    
44  from context import Context  from context import Context
45  from command import registry, Command  from command import registry, Command, ToolCommand
46  from messages import SELECTED_SHAPE, VIEW_POSITION  from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION
47    
48    from Thuban.UI.dock import DockFrame
49    from Thuban.UI.join import JoinDialog
50    
51  # the directory where the toolbar icons are stored  import resource
52  bitmapdir = os.path.join(Thuban.__path__[0], os.pardir, "Resources", "Bitmaps")  import Thuban.Model.resource
 bitmapext = ".xpm"  
53    
54    import projdialog
55  class MainWindow(wxFrame):  
56    class MainWindow(DockFrame):
57    
58        # Some messages that can be subscribed/unsubscribed directly through
59        # the MapCanvas come in fact from other objects. This is a map to
60        # map those messages to the names of the instance variables they
61        # actually come from. This delegation is implemented in the
62        # Subscribe and unsubscribed methods
63        delegated_messages = {LAYER_SELECTED: "canvas",
64                              SHAPES_SELECTED: "canvas"}
65    
66        # Methods delegated to some instance variables. The delegation is
67        # implemented in the __getattr__ method.
68        delegated_methods = {"SelectLayer": "canvas",
69                             "SelectShapes": "canvas",
70                             "SelectedLayer": "canvas",
71                             "SelectedShapes": "canvas",
72                             }
73    
74      def __init__(self, parent, ID, title, application, interactor,      def __init__(self, parent, ID, title, application, interactor,
75                   initial_message = None, size = wxSize(-1, -1)):                   initial_message = None, size = wxSize(-1, -1)):
76          wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)          DockFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
77            #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
78    
79          self.application = application          self.application = application
         self.interactor = interactor  
80    
81          self.CreateStatusBar()          self.CreateStatusBar()
82          if initial_message:          if initial_message:
# Line 63  class MainWindow(wxFrame): Line 94  class MainWindow(wxFrame):
94          # call Realize to make sure that the tools appear.          # call Realize to make sure that the tools appear.
95          toolbar.Realize()          toolbar.Realize()
96    
97    
98          # Create the map canvas          # Create the map canvas
99          canvas = view.MapCanvas(self, -1, interactor)          canvas = view.MapCanvas(self, -1)
100          canvas.Subscribe(VIEW_POSITION, self.view_position_changed)          canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
101            canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
102          self.canvas = canvas          self.canvas = canvas
103    
104            self.SetMainWindow(self.canvas)
105    
106            self.SetAutoLayout(True)
107    
108          self.init_dialogs()          self.init_dialogs()
109    
110          interactor.Subscribe(SELECTED_SHAPE, self.identify_view_on_demand)          self.ShowLegend()
111    
112          EVT_CLOSE(self, self.OnClose)          EVT_CLOSE(self, self.OnClose)
113    
114        def Subscribe(self, channel, *args):
115            """Subscribe a function to a message channel.
116    
117            If channel is one of the delegated messages call the appropriate
118            object's Subscribe method. Otherwise do nothing.
119            """
120            if channel in self.delegated_messages:
121                object = getattr(self, self.delegated_messages[channel])
122                object.Subscribe(channel, *args)
123            else:
124                print "Trying to subscribe to unsupported channel %s" % channel
125    
126        def Unsubscribe(self, channel, *args):
127            """Unsubscribe a function from a message channel.
128    
129            If channel is one of the delegated messages call the appropriate
130            object's Unsubscribe method. Otherwise do nothing.
131            """
132            if channel in self.delegated_messages:
133                object = getattr(self, self.delegated_messages[channel])
134                object.Unsubscribe(channel, *args)
135    
136        def __getattr__(self, attr):
137            """If attr is one of the delegated methods return that method
138    
139            Otherwise raise AttributeError.
140            """
141            if attr in self.delegated_methods:
142                return getattr(getattr(self, self.delegated_methods[attr]), attr)
143            raise AttributeError(attr)
144    
145      def init_ids(self):      def init_ids(self):
146          """Initialize the ids"""          """Initialize the ids"""
147          self.current_id = 6000          self.current_id = 6000
# Line 112  class MainWindow(wxFrame): Line 180  class MainWindow(wxFrame):
180          return menu_bar          return menu_bar
181    
182      def build_menu(self, menudesc):      def build_menu(self, menudesc):
183          """Build and return a wxMenu from a menudescription"""          """Return a wxMenu built from the menu description menudesc"""
184          wxmenu = wxMenu()          wxmenu = wxMenu()
185          last = None          last = None
186          for item in menudesc.items:          for item in menudesc.items:
             # here the items must all be Menu instances themselves  
187              if item is None:              if item is None:
188                  # a separator. Only add one if the last item was not a                  # a separator. Only add one if the last item was not a
189                  # separator                  # separator
# Line 169  class MainWindow(wxFrame): Line 236  class MainWindow(wxFrame):
236                              command.IsCheckCommand())                              command.IsCheckCommand())
237                  self.bind_command_events(command, ID)                  self.bind_command_events(command, ID)
238              else:              else:
239                  print "Unknown command %s" % name                  print _("Unknown command %s") % name
240    
241      def add_toolbar_command(self, toolbar, name):      def add_toolbar_command(self, toolbar, name):
242          """Add the command with name name to the toolbar toolbar.          """Add the command with name name to the toolbar toolbar.
# Line 184  class MainWindow(wxFrame): Line 251  class MainWindow(wxFrame):
251              command = registry.Command(name)              command = registry.Command(name)
252              if command is not None:              if command is not None:
253                  ID = self.get_id(name)                  ID = self.get_id(name)
254                  filename = os.path.join(bitmapdir, command.Icon()) + bitmapext                  bitmap = resource.GetBitmapResource(command.Icon(),
255                  bitmap = wxBitmap(filename, wxBITMAP_TYPE_XPM)                                                      wxBITMAP_TYPE_XPM)
256                  toolbar.AddTool(ID, bitmap,                  toolbar.AddTool(ID, bitmap,
257                                  shortHelpString = command.HelpText(),                                  shortHelpString = command.HelpText(),
258                                  isToggle = command.IsCheckCommand())                                  isToggle = command.IsCheckCommand())
259                  self.bind_command_events(command, ID)                  self.bind_command_events(command, ID)
260              else:              else:
261                  print "Unknown command %s" % name                  print _("Unknown command %s") % name
262    
263        def Context(self):
264            """Return the context object for a command invoked from this window
265            """
266            return Context(self.application, self.application.Session(), self)
267    
268      def invoke_command(self, event):      def invoke_command(self, event):
269          name = self.id_to_name.get(event.GetId())          name = self.id_to_name.get(event.GetId())
270          if name is not None:          if name is not None:
271              command = registry.Command(name)              command = registry.Command(name)
272              context = Context(self.application, self.application.Session(),              command.Execute(self.Context())
                               self)  
             command.Execute(context)  
273          else:          else:
274              print "Unknown command ID %d" % event.GetId()              print _("Unknown command ID %d") % event.GetId()
275    
276      def update_command_ui(self, event):      def update_command_ui(self, event):
277          #print "update_command_ui", self.id_to_name[event.GetId()]          #print "update_command_ui", self.id_to_name[event.GetId()]
278          context = Context(self.application, self.application.Session(), self)          context = self.Context()
279          command = registry.Command(self.id_to_name[event.GetId()])          command = registry.Command(self.id_to_name[event.GetId()])
280          if command is not None:          if command is not None:
281              event.Enable(command.Sensitive(context))              sensitive = command.Sensitive(context)
282                event.Enable(sensitive)
283                if command.IsTool() and not sensitive and command.Checked(context):
284                    # When a checked tool command is disabled deselect all
285                    # tools. Otherwise the tool would remain active but it
286                    # might lead to errors if the tools stays active. This
287                    # problem occurred in GREAT-ER and this fixes it, but
288                    # it's not clear to me whether this is really the best
289                    # way to do it (BH, 20021206).
290                    self.canvas.SelectTool(None)
291              event.SetText(command.DynText(context))              event.SetText(command.DynText(context))
292              if command.IsCheckCommand():              if command.IsCheckCommand():
293                  event.Check(command.Checked(context))                      event.Check(command.Checked(context))
294    
295      def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):      def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
296          """Run a modal message box with the given text, title and flags          """Run a modal message box with the given text, title and flags
297          and return the result"""          and return the result"""
298          dlg = wxMessageDialog(self, text, title, flags)          dlg = wxMessageDialog(self, text, title, flags)
299            dlg.CenterOnParent()
300          result = dlg.ShowModal()          result = dlg.ShowModal()
301          dlg.Destroy()          dlg.Destroy()
302          return result          return result
# Line 230  class MainWindow(wxFrame): Line 310  class MainWindow(wxFrame):
310    
311      def add_dialog(self, name, dialog):      def add_dialog(self, name, dialog):
312          if self.dialogs.has_key(name):          if self.dialogs.has_key(name):
313              raise RuntimeError("The Dialog named %s is already open" % name)              raise RuntimeError(_("The Dialog named %s is already open") % name)
314          self.dialogs[name] = dialog          self.dialogs[name] = dialog
315    
316      def dialog_open(self, name):      def dialog_open(self, name):
# Line 248  class MainWindow(wxFrame): Line 328  class MainWindow(wxFrame):
328              text = "(%10.10g, %10.10g)" % pos              text = "(%10.10g, %10.10g)" % pos
329          else:          else:
330              text = ""              text = ""
331            self.set_position_text(text)
332    
333        def set_position_text(self, text):
334            """Set the statusbar text showing the current position.
335    
336            By default the text is shown in field 0 of the status bar.
337            Override this method in derived classes to put it into a
338            different field of the statusbar.
339            """
340          self.SetStatusText(text)          self.SetStatusText(text)
341    
342      def save_modified_session(self, can_veto = 1):      def save_modified_session(self, can_veto = 1):
# Line 263  class MainWindow(wxFrame): Line 352  class MainWindow(wxFrame):
352              flags = wxYES_NO | wxICON_QUESTION              flags = wxYES_NO | wxICON_QUESTION
353              if can_veto:              if can_veto:
354                  flags = flags | wxCANCEL                  flags = flags | wxCANCEL
355              result = self.RunMessageBox("Exit",              result = self.RunMessageBox(_("Exit"),
356                                          ("The session has been modified."                                          _("The session has been modified."
357                                           " Do you want to save it?"),                                           " Do you want to save it?"),
358                                          flags)                                          flags)
359              if result == wxID_YES:              if result == wxID_YES:
# Line 273  class MainWindow(wxFrame): Line 362  class MainWindow(wxFrame):
362              result = wxID_NO              result = wxID_NO
363          return result          return result
364    
365        def prepare_new_session(self):
366            for d in self.dialogs.values():
367                if not isinstance(d, tree.SessionTreeView):
368                    d.Close()
369    
370      def NewSession(self):      def NewSession(self):
371          self.save_modified_session()          if self.save_modified_session() != wxID_CANCEL:
372          self.application.SetSession(create_empty_session())              self.prepare_new_session()
373                self.application.SetSession(create_empty_session())
374    
375      def OpenSession(self):      def OpenSession(self):
376          self.save_modified_session()          if self.save_modified_session() != wxID_CANCEL:
377          dlg = wxFileDialog(self, "Select a session file", ".", "",              dlg = wxFileDialog(self, _("Open Session"), ".", "",
378                             "*.thuban", wxOPEN)                                 "Thuban Session File (*.thuban)|*.thuban",
379          if dlg.ShowModal() == wxID_OK:                                 wxOPEN)
380              self.application.OpenSession(dlg.GetPath())              if dlg.ShowModal() == wxID_OK:
381          dlg.Destroy()                  self.prepare_new_session()
382                    self.application.OpenSession(dlg.GetPath())
383                dlg.Destroy()
384    
385      def SaveSession(self):      def SaveSession(self):
386          if self.application.session.filename == None:          if self.application.session.filename == None:
387              self.SaveSessionAs()              self.SaveSessionAs()
388          self.application.SaveSession()          else:
389                self.application.SaveSession()
390    
391      def SaveSessionAs(self):      def SaveSessionAs(self):
392          dlg = wxFileDialog(self, "Enter a filename for session", ".", "",          dlg = wxFileDialog(self, _("Save Session As"), ".", "",
393                             "*.thuban", wxOPEN)                             "Thuban Session File (*.thuban)|*.thuban",
394                               wxSAVE|wxOVERWRITE_PROMPT)
395          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
396              self.application.session.SetFilename(dlg.GetPath())              self.application.session.SetFilename(dlg.GetPath())
397              self.application.SaveSession()              self.application.SaveSession()
398          dlg.Destroy()          dlg.Destroy()
399    
400      def Exit(self):      def Exit(self):
401          self.Close(false)          self.Close(False)
402    
403      def OnClose(self, event):      def OnClose(self, event):
404          result = self.save_modified_session(can_veto = event.CanVeto())          result = self.save_modified_session(can_veto = event.CanVeto())
405          if result == wxID_CANCEL:          if result == wxID_CANCEL:
406              event.Veto()              event.Veto()
407          else:          else:
408                # FIXME: it would be better to tie the unsubscription to
409                # wx's destroy event, but that isn't implemented for wxGTK
410                # yet.
411                self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
412                DockFrame.OnClose(self, event)
413                for dlg in self.dialogs.values():
414                    dlg.Destroy()
415                self.canvas.Destroy()
416              self.Destroy()              self.Destroy()
417    
418      def SetMap(self, map):      def SetMap(self, map):
419          self.canvas.SetMap(map)          self.canvas.SetMap(map)
420            self.__SetTitle(map.Title())
421    
422      def ShowSessionTree(self):          dialog = self.FindRegisteredDock("legend")
423            if dialog is not None:
424                dialog.GetPanel().SetMap(self.Map())
425    
426        def Map(self):
427            """Return the map displayed by this mainwindow"""
428    
429            return self.canvas.Map()
430    
431        def ToggleSessionTree(self):
432            """If the session tree is shown close it otherwise create a new tree"""
433          name = "session_tree"          name = "session_tree"
434          dialog = self.get_open_dialog(name)          dialog = self.get_open_dialog(name)
435          if dialog is None:          if dialog is None:
436              dialog = tree.SessionTreeView(self, self.application, name)              dialog = tree.SessionTreeView(self, self.application, name)
437              self.add_dialog(name, dialog)              self.add_dialog(name, dialog)
438              dialog.Show(true)              dialog.Show(True)
439          else:          else:
440              # FIXME: bring dialog to front here              dialog.Close()
441              pass  
442        def SessionTreeShown(self):
443            """Return true iff the session tree is currently shown"""
444            return self.get_open_dialog("session_tree") is not None
445    
446      def About(self):      def About(self):
447          self.RunMessageBox("About",          self.RunMessageBox(_("About"),
448                             ("Thuban is a program for\n"                             _("Thuban %s\n"
449                                #"Build Date: %s\n"
450                                "using:\n"
451                                "  %s\n"
452                                "  %s\n\n"
453                                "Thuban is a program for\n"
454                              "exploring geographic data.\n"                              "exploring geographic data.\n"
455                              "Copyright (C) 2001 Intevation GmbH.\n"                              "Copyright (C) 2001-2003 Intevation GmbH.\n"
456                              "Thuban is licensed under the GPL"),                              "Thuban is licensed under the GNU GPL"
457                                % (Thuban.version.longversion,
458                                   "wxPython %s" % wxPython_version,
459                                   "Python %d.%d.%d" % sys.version_info[:3]
460                                  )),
461    #                           % __ThubanVersion__), #__BuildDate__)),
462                             wxOK | wxICON_INFORMATION)                             wxOK | wxICON_INFORMATION)
463    
464      def AddLayer(self):      def AddLayer(self):
465          dlg = wxFileDialog(self, "Select a data file", ".", "", "*.*",          dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
466                             wxOPEN)                             wxOPEN)
467          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
468              filename = dlg.GetPath()              filename = dlg.GetPath()
469              title = os.path.splitext(os.path.basename(filename))[0]              title = os.path.splitext(os.path.basename(filename))[0]
             layer = Layer(title, filename)  
470              map = self.canvas.Map()              map = self.canvas.Map()
471              has_layers = map.HasLayers()              has_layers = map.HasLayers()
472              try:              try:
473                    store = self.application.Session().OpenShapefile(filename)
474                except IOError:
475                    # the layer couldn't be opened
476                    self.RunMessageBox(_("Add Layer"),
477                                       _("Can't open the file '%s'.") % filename)
478                else:
479                    layer = Layer(title, store)
480                  map.AddLayer(layer)                  map.AddLayer(layer)
481                    if not has_layers:
482                        # if we're adding a layer to an empty map, fit the
483                        # new map to the window
484                        self.canvas.FitMapToWindow()
485            dlg.Destroy()
486    
487        def AddRasterLayer(self):
488            dlg = wxFileDialog(self, _("Select an image file"), ".", "", "*.*",
489                               wxOPEN)
490            if dlg.ShowModal() == wxID_OK:
491                filename = dlg.GetPath()
492                title = os.path.splitext(os.path.basename(filename))[0]
493                map = self.canvas.Map()
494                has_layers = map.HasLayers()
495                try:
496                    layer = RasterLayer(title, filename)
497              except IOError:              except IOError:
498                  # the layer couldn't be opened                  # the layer couldn't be opened
499                  self.RunMessageBox("Add Layer",                  self.RunMessageBox(_("Add Image Layer"),
500                                     "Can't open the file '%s'." % filename)                                     _("Can't open the file '%s'.") % filename)
501              else:              else:
502                    map.AddLayer(layer)
503                  if not has_layers:                  if not has_layers:
504                      # if we're adding a layer to an empty map, for the                      # if we're adding a layer to an empty map, fit the
505                      # new map to the window                      # new map to the window
506                      self.canvas.FitMapToWindow()                      self.canvas.FitMapToWindow()
507          dlg.Destroy()          dlg.Destroy()
# Line 357  class MainWindow(wxFrame): Line 511  class MainWindow(wxFrame):
511          if layer is not None:          if layer is not None:
512              self.canvas.Map().RemoveLayer(layer)              self.canvas.Map().RemoveLayer(layer)
513    
514        def CanRemoveLayer(self):
515            """Return true if the currently selected layer can be deleted.
516    
517            If no layer is selected return False.
518    
519            The return value of this method determines whether the remove
520            layer command is sensitive in menu.
521            """
522            layer = self.current_layer()
523            if layer is not None:
524                return self.canvas.Map().CanRemoveLayer(layer)
525            return False
526    
527      def RaiseLayer(self):      def RaiseLayer(self):
528          layer = self.current_layer()          layer = self.current_layer()
529          if layer is not None:          if layer is not None:
# Line 372  class MainWindow(wxFrame): Line 539  class MainWindow(wxFrame):
539    
540          If no layer is selected, return None          If no layer is selected, return None
541          """          """
542          return self.interactor.SelectedLayer()          return self.canvas.SelectedLayer()
543    
544      def has_selected_layer(self):      def has_selected_layer(self):
545          """Return true if a layer is currently selected"""          """Return true if a layer is currently selected"""
546          return self.interactor.HasSelectedLayer()          return self.canvas.HasSelectedLayer()
547    
548      def choose_color(self):      def has_selected_shapes(self):
549          """Run the color selection dialog and return the selected color.          """Return true if a shape is currently selected"""
550            return self.canvas.HasSelectedShapes()
551    
552          If the user cancels, return None.      def HideLayer(self):
         """  
         dlg = wxColourDialog(self)  
         color = None  
         if dlg.ShowModal() == wxID_OK:  
             data = dlg.GetColourData()  
             wxc = data.GetColour()  
             color = Color(wxc.Red() / 255.0,  
                           wxc.Green() / 255.0,  
                           wxc.Blue() / 255.0)  
         dlg.Destroy()  
         return color  
   
     def LayerFillColor(self):  
         layer = self.current_layer()  
         if layer is not None:  
             color = self.choose_color()  
             if color is not None:  
                 layer.SetFill(color)  
   
     def LayerTransparentFill(self):  
553          layer = self.current_layer()          layer = self.current_layer()
554          if layer is not None:          if layer is not None:
555              layer.SetFill(None)              layer.SetVisible(0)
556    
557      def LayerOutlineColor(self):      def ShowLayer(self):
558          layer = self.current_layer()          layer = self.current_layer()
559          if layer is not None:          if layer is not None:
560              color = self.choose_color()              layer.SetVisible(1)
             if color is not None:  
                 layer.SetStroke(color)  
561    
562      def LayerNoOutline(self):      def DuplicateLayer(self):
563            """Ceate a new layer above the selected layer with the same shapestore
564            """
565          layer = self.current_layer()          layer = self.current_layer()
566          if layer is not None:          if layer is not None and hasattr(layer, "ShapeStore"):
567              layer.SetStroke(None)              new_layer = Layer(_("Copy of `%s'") % layer.Title(),
568                                  layer.ShapeStore(),
569                                  projection = layer.GetProjection())
570                new_classification = copy.deepcopy(layer.GetClassification())
571                new_layer.SetClassification(new_classification)
572                self.Map().AddLayer(new_layer)
573    
574      def HideLayer(self):      def CanDuplicateLayer(self):
575            """Return whether the DuplicateLayer method can create a duplicate"""
576          layer = self.current_layer()          layer = self.current_layer()
577          if layer is not None:          return layer is not None and hasattr(layer, "ShapeStore")
             layer.SetVisible(0)  
           
     def ShowLayer(self):  
         layer = self.current_layer()  
         if layer is not None:  
             layer.SetVisible(1)  
578    
579      def LayerShowTable(self):      def LayerShowTable(self):
580          layer = self.current_layer()          layer = self.current_layer()
581          if layer is not None:          if layer is not None:
582              table = layer.table              table = layer.ShapeStore().Table()
583              name = "table_view" + str(id(table))              name = "table_view" + str(id(table))
584              dialog = self.get_open_dialog(name)              dialog = self.get_open_dialog(name)
585              if dialog is None:              if dialog is None:
586                  dialog = tableview.TableFrame(self, self.interactor, name,                  dialog = tableview.LayerTableFrame(self, name,
587                                                "Table: %s" % layer.Title(),                                           _("Layer Table: %s") % layer.Title(),
588                                                layer, table)                                           layer, table)
589                  self.add_dialog(name, dialog)                  self.add_dialog(name, dialog)
590                  dialog.Show(true)                  dialog.Show(True)
591              else:              else:
592                  # FIXME: bring dialog to front here                  # FIXME: bring dialog to front here
593                  pass                  pass
594    
595      def Projection(self):      def MapProjection(self):
596          map = self.canvas.Map()  
597          proj = map.projection          name = "map_projection"
598          if proj is None:          dialog = self.get_open_dialog(name)
599              proj4Dlg = proj4dialog.Proj4Dialog(NULL, None, map.BoundingBox())  
600          else:          if dialog is None:
601              proj4Dlg = proj4dialog.Proj4Dialog(NULL, map.projection.params,              map = self.canvas.Map()
602                                                 map.BoundingBox())              dialog = projdialog.ProjFrame(self, name,
603          if proj4Dlg.ShowModal() == wxID_OK:                       _("Map Projection: %s") % map.Title(), map)
604              params = proj4Dlg.GetParams()              self.add_dialog(name, dialog)
605              if params is not None:              dialog.Show()
606                  proj = Projection(params)          dialog.Raise()
607    
608        def LayerProjection(self):
609    
610            layer = self.current_layer()
611    
612            name = "layer_projection" + str(id(layer))
613            dialog = self.get_open_dialog(name)
614    
615            if dialog is None:
616                map = self.canvas.Map()
617                dialog = projdialog.ProjFrame(self, name,
618                         _("Layer Projection: %s") % layer.Title(), layer)
619                self.add_dialog(name, dialog)
620                dialog.Show()
621            dialog.Raise()
622    
623        def LayerEditProperties(self):
624    
625            #
626            # the menu option for this should only be available if there
627            # is a current layer, so we don't need to check if the
628            # current layer is None
629            #
630    
631            layer = self.current_layer()
632            self.OpenLayerProperties(layer)
633    
634        def OpenLayerProperties(self, layer, group = None):
635            name = "layer_properties" + str(id(layer))
636            dialog = self.get_open_dialog(name)
637    
638            if dialog is None:
639                dialog = Classifier(self, name, self.Map(), layer, group)
640                self.add_dialog(name, dialog)
641                dialog.Show()
642            dialog.Raise()
643    
644        def LayerJoinTable(self):
645            layer = self.canvas.SelectedLayer()
646            if layer is not None:
647                dlg = JoinDialog(self, _("Join Layer with Table"),
648                                 self.application.session,
649                                 layer = layer)
650                dlg.ShowModal()
651    
652        def LayerUnjoinTable(self):
653            layer = self.canvas.SelectedLayer()
654            if layer is not None:
655                orig_store = layer.ShapeStore().OrigShapeStore()
656                if orig_store:
657                    layer.SetShapeStore(orig_store)
658    
659        def ShowLegend(self):
660            if not self.LegendShown():
661                self.ToggleLegend()
662    
663        def ToggleLegend(self):
664            """Show the legend if it's not shown otherwise hide it again"""
665            name = "legend"
666            dialog = self.FindRegisteredDock(name)
667    
668            if dialog is None:
669                dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
670                legend.LegendPanel(dialog, None, self)
671                dialog.Dock()
672                dialog.GetPanel().SetMap(self.Map())
673                dialog.Show()
674            else:
675                dialog.Show(not dialog.IsShown())
676    
677            self.canvas.FitMapToWindow()
678    
679        def LegendShown(self):
680            """Return true iff the legend is currently open"""
681            dialog = self.FindRegisteredDock("legend")
682            return dialog is not None and dialog.IsShown()
683    
684        def TableOpen(self):
685            dlg = wxFileDialog(self, _("Open Table"), ".", "",
686                               _("DBF Files (*.dbf)") + "|*.dbf|" +
687                               #_("CSV Files (*.csv)") + "|*.csv|" +
688                               _("All Files (*.*)") + "|*.*",
689                               wxOPEN)
690            if dlg.ShowModal() == wxID_OK:
691                filename = dlg.GetPath()
692                dlg.Destroy()
693                try:
694                    table = self.application.session.OpenTableFile(filename)
695                except IOError:
696                    # the layer couldn't be opened
697                    self.RunMessageBox(_("Open Table"),
698                                       _("Can't open the file '%s'.") % filename)
699              else:              else:
700                  proj = None                  self.ShowTableView(table)
701              map.SetProjection(proj)  
702          proj4Dlg.Destroy()      def TableClose(self):
703            tables = self.application.session.UnreferencedTables()
704    
705            lst = [(t.Title(), t) for t in tables]
706            lst.sort()
707            titles = [i[0] for i in lst]
708            dlg = wxMultipleChoiceDialog(self, _("Pick the tables to close:"),
709                                         _("Close Table"), titles,
710                                         size = (400, 300),
711                                         style = wxDEFAULT_DIALOG_STYLE |
712                                                 wxRESIZE_BORDER)
713            if dlg.ShowModal() == wxID_OK:
714                for i in dlg.GetValue():
715                    self.application.session.RemoveTable(lst[i][1])
716    
717    
718        def TableShow(self):
719            """Offer a multi-selection dialog for tables to be displayed
720    
721            The windows for the selected tables are opened or brought to
722            the front.
723            """
724            tables = self.application.session.Tables()
725    
726            lst = [(t.Title(), t) for t in tables]
727            lst.sort()
728            titles = [i[0] for i in lst]
729            dlg = wxMultipleChoiceDialog(self, _("Pick the table to show:"),
730                                         _("Show Table"), titles,
731                                         size = (400,300),
732                                         style = wxDEFAULT_DIALOG_STYLE |
733                                                 wxRESIZE_BORDER)
734            if (dlg.ShowModal() == wxID_OK):
735                for i in dlg.GetValue():
736                    # XXX: if the table belongs to a layer, open a
737                    # LayerTableFrame instead of QueryTableFrame
738                    self.ShowTableView(lst[i][1])
739    
740        def TableJoin(self):
741            dlg = JoinDialog(self, _("Join Tables"), self.application.session)
742            dlg.ShowModal()
743    
744        def ShowTableView(self, table):
745            """Open a table view for the table and optionally"""
746            name = "table_view%d" % id(table)
747            dialog = self.get_open_dialog(name)
748            if dialog is None:
749                dialog = tableview.QueryTableFrame(self, name,
750                                                   _("Table: %s") % table.Title(),
751                                                   table)
752                self.add_dialog(name, dialog)
753                dialog.Show(True)
754            # FIXME: else bring dialog to front
755    
756        def TableRename(self):
757            """Let the user rename a table"""
758    
759            # First, let the user select a table
760            tables = self.application.session.Tables()
761            lst = [(t.Title(), t) for t in tables]
762            lst.sort()
763            titles = [i[0] for i in lst]
764            dlg = wxMultipleChoiceDialog(self, _("Pick the table to rename:"),
765                                         _("Rename Table"), titles,
766                                         size = (400,300),
767                                         style = wxDEFAULT_DIALOG_STYLE |
768                                                 wxRESIZE_BORDER)
769            if (dlg.ShowModal() == wxID_OK):
770                to_rename = [lst[i][1] for i in dlg.GetValue()]
771                dlg.Destroy()
772            else:
773                to_rename = []
774    
775            # Second, let the user rename the layers
776            for table in to_rename:
777                dlg = wxTextEntryDialog(self, "Table Title: ", "Rename Table",
778                                        table.Title())
779                try:
780                    if dlg.ShowModal() == wxID_OK:
781                        title = dlg.GetValue()
782                        if title != "":
783                            table.SetTitle(title)
784    
785                            # Make sure the session is marked as modified.
786                            # FIXME: This should be handled automatically,
787                            # but that requires more changes to the tables
788                            # than I have time for currently.
789                            self.application.session.changed()
790                finally:
791                    dlg.Destroy()
792    
793    
794      def ZoomInTool(self):      def ZoomInTool(self):
795          self.canvas.ZoomInTool()          self.canvas.ZoomInTool()
# Line 480  class MainWindow(wxFrame): Line 810  class MainWindow(wxFrame):
810      def FullExtent(self):      def FullExtent(self):
811          self.canvas.FitMapToWindow()          self.canvas.FitMapToWindow()
812    
813        def FullLayerExtent(self):
814            self.canvas.FitLayerToWindow(self.current_layer())
815    
816        def FullSelectionExtent(self):
817            self.canvas.FitSelectedToWindow()
818    
819        def ExportMap(self):
820            self.canvas.Export()
821    
822      def PrintMap(self):      def PrintMap(self):
823          self.canvas.Print()          self.canvas.Print()
824    
825      def identify_view_on_demand(self, layer, shape):      def RenameMap(self):
826            dlg = wxTextEntryDialog(self, "Map Title: ", "Rename Map",
827                                    self.Map().Title())
828            if dlg.ShowModal() == wxID_OK:
829                title = dlg.GetValue()
830                if title != "":
831                    self.Map().SetTitle(title)
832                    self.__SetTitle(title)
833    
834            dlg.Destroy()
835    
836        def RenameLayer(self):
837            """Let the user rename the currently selected layer"""
838            layer = self.current_layer()
839            if layer is not None:
840                dlg = wxTextEntryDialog(self, "Layer Title: ", "Rename Layer",
841                                        layer.Title())
842                try:
843                    if dlg.ShowModal() == wxID_OK:
844                        title = dlg.GetValue()
845                        if title != "":
846                            layer.SetTitle(title)
847                finally:
848                    dlg.Destroy()
849    
850        def identify_view_on_demand(self, layer, shapes):
851            """Subscribed to the canvas' SHAPES_SELECTED message
852    
853            If the current tool is the identify tool, at least one shape is
854            selected and the identify dialog is not shown, show the dialog.
855            """
856            # If the selection has become empty we don't need to do
857            # anything. Otherwise it could happen that the dialog was popped
858            # up when the selection became empty, e.g. when a new selection
859            # is opened while the identify tool is active and dialog had
860            # been closed
861            if not shapes:
862                return
863    
864          name = "identify_view"          name = "identify_view"
865          if self.canvas.CurrentTool() == "IdentifyTool":          if self.canvas.CurrentTool() == "IdentifyTool":
866              if not self.dialog_open(name):              if not self.dialog_open(name):
867                  dialog = identifyview.IdentifyView(self, self.interactor, name)                  dialog = identifyview.IdentifyView(self, name)
868                  self.add_dialog(name, dialog)                  self.add_dialog(name, dialog)
869                  dialog.Show(true)                  dialog.Show(True)
870              else:              else:
871                  # FIXME: bring dialog to front?                  # FIXME: bring dialog to front?
872                  pass                  pass
873    
874        def __SetTitle(self, title):
875            self.SetTitle("Thuban - " + title)
876    
877  #  #
878  # Define all the commands available in the main window  # Define all the commands available in the main window
879  #  #
# Line 505  def call_method(context, methodname, *ar Line 885  def call_method(context, methodname, *ar
885      apply(getattr(context.mainwindow, methodname), args)      apply(getattr(context.mainwindow, methodname), args)
886    
887  def _method_command(name, title, method, helptext = "",  def _method_command(name, title, method, helptext = "",
888                      icon = "", sensitive = None):                      icon = "", sensitive = None, checked = None):
889      """Add a command implemented by a method of the mainwindow object"""      """Add a command implemented by a method of the mainwindow object"""
890      registry.Add(Command(name, title, call_method, args=(method,),      registry.Add(Command(name, title, call_method, args=(method,),
891                           helptext = helptext, icon = icon,                           helptext = helptext, icon = icon,
892                           sensitive = sensitive))                           sensitive = sensitive, checked = checked))
893    
894  def make_check_current_tool(toolname):  def make_check_current_tool(toolname):
895      """Return a function that tests if the currently active tool is toolname      """Return a function that tests if the currently active tool is toolname
# Line 523  def make_check_current_tool(toolname): Line 903  def make_check_current_tool(toolname):
903      return check_current_tool      return check_current_tool
904    
905  def _tool_command(name, title, method, toolname, helptext = "",  def _tool_command(name, title, method, toolname, helptext = "",
906                    icon = ""):                    icon = "", sensitive = None):
907      """Add a tool command"""      """Add a tool command"""
908      registry.Add(Command(name, title, call_method, args=(method,),      registry.Add(ToolCommand(name, title, call_method, args=(method,),
909                           helptext = helptext, icon = icon,                               helptext = helptext, icon = icon,
910                           checked = make_check_current_tool(toolname)))                               checked = make_check_current_tool(toolname),
911                                 sensitive = sensitive))
912    
913  def _has_selected_layer(context):  def _has_selected_layer(context):
914      """Return true if a layer is selected in the context"""      """Return true if a layer is selected in the context"""
915      return context.mainwindow.has_selected_layer()      return context.mainwindow.has_selected_layer()
916    
917    def _has_selected_shapes(context):
918        """Return true if a layer is selected in the context"""
919        return context.mainwindow.has_selected_shapes()
920    
921    def _can_remove_layer(context):
922        return context.mainwindow.CanRemoveLayer()
923    
924  def _has_tree_window_shown(context):  def _has_tree_window_shown(context):
925      """Return true if the tree window is shown"""      """Return true if the tree window is shown"""
926      return context.mainwindow.get_open_dialog("session_tree") is None      return context.mainwindow.SessionTreeShown()
927    
928    def _has_visible_map(context):
929        """Return true iff theres a visible map in the mainwindow.
930    
931        A visible map is a map with at least one visible layer."""
932        map = context.mainwindow.Map()
933        if map is not None:
934            for layer in map.Layers():
935                if layer.Visible():
936                    return 1
937        return 0
938    
939    def _has_legend_shown(context):
940        """Return true if the legend window is shown"""
941        return context.mainwindow.LegendShown()
942    
943    def _has_gdal_support(context):
944        """Return True if the GDAL is available"""
945        return Thuban.Model.resource.has_gdal_support()
946    
947  # File menu  # File menu
948  _method_command("new_session", "&New Session", "NewSession")  _method_command("new_session", _("&New Session"), "NewSession",
949  _method_command("open_session", "&Open Session", "OpenSession")                  helptext = _("Start a new session"))
950  _method_command("save_session", "&Save Session", "SaveSession")  _method_command("open_session", _("&Open Session..."), "OpenSession",
951  _method_command("save_session_as", "Save Session &As", "SaveSessionAs")                  helptext = _("Open a session file"))
952  _method_command("show_session_tree", "Show Session &Tree", "ShowSessionTree",  _method_command("save_session", _("&Save Session"), "SaveSession",
953                  sensitive = _has_tree_window_shown)                  helptext =_("Save this session to the file it was opened from"))
954  _method_command("exit", "&Exit", "Exit")  _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs",
955                    helptext = _("Save this session to a new file"))
956    _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
957                    checked = _has_tree_window_shown,
958                    helptext = _("Toggle on/off the session tree analysis window"))
959    _method_command("toggle_legend", _("Legend"), "ToggleLegend",
960                    checked = _has_legend_shown,
961                    helptext = _("Toggle Legend on/off"))
962    _method_command("exit", _("E&xit"), "Exit",
963                    helptext = _("Finish working with Thuban"))
964    
965  # Help menu  # Help menu
966  _method_command("help_about", "&About", "About")  _method_command("help_about", _("&About..."), "About",
967                    helptext = _("Info about Thuban authors, version and modules"))
968    
969    
970  # Map menu  # Map menu
971  _method_command("map_projection", "Pro&jection", "Projection")  _method_command("map_projection", _("Pro&jection..."), "MapProjection",
972                    helptext = _("Set or change the map projection"))
973    
974  _tool_command("map_zoom_in_tool", "&Zoom in", "ZoomInTool", "ZoomInTool",  _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
975                helptext = "Switch to map-mode 'zoom-in'", icon = "zoom_in")                helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
976  _tool_command("map_zoom_out_tool", "Zoom &out", "ZoomOutTool", "ZoomOutTool",                sensitive = _has_visible_map)
977                helptext = "Switch to map-mode 'zoom-out'", icon = "zoom_out")  _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
978  _tool_command("map_pan_tool", "&Pan", "PanTool", "PanTool",                helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
979                helptext = "Switch to map-mode 'pan'", icon = "pan")                sensitive = _has_visible_map)
980  _tool_command("map_identify_tool", "&Identify", "IdentifyTool", "IdentifyTool",  _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
981                helptext = "Switch to map-mode 'identify'", icon = "identify")                helptext = _("Switch to map-mode 'pan'"), icon = "pan",
982  _tool_command("map_label_tool", "&Label", "LabelTool", "LabelTool",                sensitive = _has_visible_map)
983                helptext = "Add/Remove labels", icon = "label")  _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
984  _method_command("map_full_extent", "&Full extent", "FullExtent",                "IdentifyTool",
985                 helptext = "Full Extent", icon = "fullextent")                helptext = _("Switch to map-mode 'identify'"), icon = "identify",
986  _method_command("map_print", "Prin&t", "PrintMap", helptext = "Print the map")                sensitive = _has_visible_map)
987    _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
988                  helptext = _("Add/Remove labels"), icon = "label",
989                  sensitive = _has_visible_map)
990    _method_command("map_full_extent", _("&Full extent"), "FullExtent",
991                   helptext = _("Zoom to the full map extent"), icon = "fullextent",
992                  sensitive = _has_visible_map)
993    _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
994                    helptext = _("Zoom to the full layer extent"),
995                    icon = "fulllayerextent", sensitive = _has_selected_layer)
996    _method_command("selected_full_extent", _("&Full selection extent"),
997                    "FullSelectionExtent",
998                    helptext = _("Zoom to the full selection extent"),
999                    icon = "fullselextent", sensitive = _has_selected_shapes)
1000    _method_command("map_export", _("E&xport"), "ExportMap",
1001                    helptext = _("Export the map to file"))
1002    _method_command("map_print", _("Prin&t"), "PrintMap",
1003                    helptext = _("Print the map"))
1004    _method_command("map_rename", _("&Rename..."), "RenameMap",
1005                    helptext = _("Rename the map"))
1006    _method_command("layer_add", _("&Add Layer..."), "AddLayer",
1007                    helptext = _("Add a new layer to the map"))
1008    _method_command("rasterlayer_add", _("&Add Image Layer..."), "AddRasterLayer",
1009                    helptext = _("Add a new image layer to the map"),
1010                    sensitive = _has_gdal_support)
1011    _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
1012                    helptext = _("Remove selected layer"),
1013                    sensitive = _can_remove_layer)
1014    
1015  # Layer menu  # Layer menu
1016  _method_command("layer_add", "&Add Layer", "AddLayer",  _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
1017                  helptext = "Add a new layer to active map")                  sensitive = _has_selected_layer,
1018  _method_command("layer_remove", "&Remove Layer", "RemoveLayer",                  helptext = _("Specify projection for selected layer"))
1019                  helptext = "Remove selected layer(s)",  _method_command("layer_duplicate", _("&Duplicate"), "DuplicateLayer",
1020                  sensitive = _has_selected_layer)                  helptext = _("Duplicate selected layer"),
1021  _method_command("layer_fill_color", "&Fill Color", "LayerFillColor",            sensitive = lambda context: context.mainwindow.CanDuplicateLayer())
1022                  helptext = "Set the fill color of selected layer(s)",  _method_command("layer_rename", _("Re&name ..."), "RenameLayer",
1023                  sensitive = _has_selected_layer)                  helptext = _("Rename selected layer"),
 _method_command("layer_transparent_fill", "&Transparent Fill",  
                 "LayerTransparentFill",  
                 helptext = "Do not fill the selected layer(s)",  
                 sensitive = _has_selected_layer)  
 _method_command("layer_outline_color", "&Outline Color", "LayerOutlineColor",  
                 helptext = "Set the outline color of selected layer(s)",  
                 sensitive = _has_selected_layer)  
 _method_command("layer_no_outline", "&No Outline", "LayerNoOutline",  
                 helptext = "Do not draw the outline of the selected layer(s)",  
1024                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1025  _method_command("layer_raise", "&Raise", "RaiseLayer",  _method_command("layer_raise", _("&Raise"), "RaiseLayer",
1026                  helptext = "Raise selected layer(s)",                  helptext = _("Raise selected layer"),
1027                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1028  _method_command("layer_lower", "&Lower", "LowerLayer",  _method_command("layer_lower", _("&Lower"), "LowerLayer",
1029                  helptext = "Lower selected layer(s)",                  helptext = _("Lower selected layer"),
1030                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1031  _method_command("layer_show", "&Show", "ShowLayer",  _method_command("layer_show", _("&Show"), "ShowLayer",
1032                  helptext = "Make selected layer(s) visible",                  helptext = _("Make selected layer visible"),
1033                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1034  _method_command("layer_hide", "&Hide", "HideLayer",  _method_command("layer_hide", _("&Hide"), "HideLayer",
1035                  helptext = "Make selected layer(s) unvisible",                  helptext = _("Make selected layer unvisible"),
1036                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1037  _method_command("layer_show_table", "Show Ta&ble", "LayerShowTable",  _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
1038                  helptext = "Show the selected layer's table",                  helptext = _("Show the selected layer's table"),
1039                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1040    _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
1041                    sensitive = _has_selected_layer,
1042                    helptext = _("Edit the properties of the selected layer"))
1043    _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
1044                    sensitive = _has_selected_layer,
1045                    helptext = _("Join and attach a table to the selected layer"))
1046    
1047    def _can_unjoin(context):
1048        """Return whether the Layer/Unjoin command can be executed.
1049    
1050  # the menu structure      This is the case if a layer is selected and that layer has a
1051  main_menu = Menu("<main>", "<main>",      shapestore that has an original shapestore.
1052                   [Menu("file", "&File",      """
1053                         ["new_session", "open_session", None,      layer = context.mainwindow.SelectedLayer()
1054                          "save_session", "save_session_as", None,      if layer is None:
1055                          "show_session_tree", None,          return 0
1056                          "exit"]),      getstore = getattr(layer, "ShapeStore", None)
1057                    Menu("map", "&Map",      if getstore is not None:
1058                         ["layer_add", "layer_remove",          return getstore().OrigShapeStore() is not None
1059        else:
1060            return 0
1061    _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
1062                    sensitive = _can_unjoin,
1063                    helptext = _("Undo the last join operation"))
1064    
1065    
1066    def _has_tables(context):
1067        return bool(context.session.Tables())
1068    
1069    # Table menu
1070    _method_command("table_open", _("&Open..."), "TableOpen",
1071                    helptext = _("Open a DBF-table from a file"))
1072    _method_command("table_close", _("&Close..."), "TableClose",
1073           sensitive = lambda context: bool(context.session.UnreferencedTables()),
1074                    helptext = _("Close one or more tables from a list"))
1075    _method_command("table_rename", _("&Rename..."), "TableRename",
1076                    sensitive = _has_tables,
1077                    helptext = _("Rename one or more tables"))
1078    _method_command("table_show", _("&Show..."), "TableShow",
1079                    sensitive = _has_tables,
1080                    helptext = _("Show one or more tables in a dialog"))
1081    _method_command("table_join", _("&Join..."), "TableJoin",
1082                    sensitive = _has_tables,
1083                    helptext = _("Join two tables creating a new one"))
1084    
1085    #  Export only under Windows ...
1086    map_menu = ["layer_add", "rasterlayer_add", "layer_remove",
1087                          None,                          None,
1088                            "map_rename",
1089                          "map_projection",                          "map_projection",
1090                          None,                          None,
1091                          "map_zoom_in_tool", "map_zoom_out_tool",                          "map_zoom_in_tool", "map_zoom_out_tool",
1092                          "map_pan_tool", "map_identify_tool", "map_label_tool",                          "map_pan_tool",
1093                            "map_full_extent",
1094                            "layer_full_extent",
1095                            "selected_full_extent",
1096                          None,                          None,
1097                          "map_full_extent",                          "map_identify_tool", "map_label_tool",
1098                          None,                          None,
1099                          "map_print"]),                          "toggle_legend",
1100                    Menu("layer", "&Layer",                          None]
1101                         ["layer_fill_color", "layer_transparent_fill",  if wxPlatform == '__WXMSW__':
1102                          "layer_outline_color", "layer_no_outline",      map_menu.append("map_export")
1103    map_menu.append("map_print")
1104    
1105    # the menu structure
1106    main_menu = Menu("<main>", "<main>",
1107                     [Menu("file", _("&File"),
1108                           ["new_session", "open_session", None,
1109                            "save_session", "save_session_as", None,
1110                            "toggle_session_tree", None,
1111                            "exit"]),
1112                      Menu("map", _("&Map"), map_menu),
1113                      Menu("layer", _("&Layer"),
1114                           ["layer_rename", "layer_duplicate",
1115                          None,                          None,
1116                          "layer_raise", "layer_lower",                          "layer_raise", "layer_lower",
1117                          None,                          None,
1118                          "layer_show", "layer_hide",                          "layer_show", "layer_hide",
1119                          None,                          None,
1120                          "layer_show_table"]),                          "layer_projection",
1121                    Menu("help", "&Help",                          None,
1122                            "layer_show_table",
1123                            "layer_jointable",
1124                            "layer_unjointable",
1125                            None,
1126                            "layer_properties"]),
1127                      Menu("table", _("&Table"),
1128                           ["table_open", "table_close", "table_rename",
1129                           None,
1130                           "table_show",
1131                           None,
1132                           "table_join"]),
1133                      Menu("help", _("&Help"),
1134                         ["help_about"])])                         ["help_about"])])
1135    
1136  # the main toolbar  # the main toolbar
1137    
1138  main_toolbar = Menu("<toolbar>", "<toolbar>",  main_toolbar = Menu("<toolbar>", "<toolbar>",
1139                      ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",                      ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
1140                       "map_identify_tool", "map_label_tool", "map_full_extent"])                       "map_full_extent",
1141                         "layer_full_extent",
1142                         "selected_full_extent",
1143                         None,
1144                         "map_identify_tool", "map_label_tool"])

Legend:
Removed from v.270  
changed lines
  Added in v.1233

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26