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

Legend:
Removed from v.278  
changed lines
  Added in v.1219

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26