/[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

trunk/thuban/Thuban/UI/mainwindow.py revision 1070 by bh, Tue May 27 15:09:31 2003 UTC branches/WIP-pyshapelib-bramz/Thuban/UI/mainwindow.py revision 2734 by bramz, Thu Mar 1 12:42:59 2007 UTC
# Line 1  Line 1 
1  # Copyright (C) 2001, 2002, 2003 by Intevation GmbH  # Copyright (C) 2001, 2002, 2003, 2004, 2005 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]>
# Line 12  The main window Line 12  The main window
12  """  """
13    
14  __version__ = "$Revision$"  __version__ = "$Revision$"
15    # $Source$
16  __ThubanVersion__ = "0.2" #"$THUBAN_0_2$"  # $Id$
 #__BuildDate__ = "$Date$"  
17    
18  import os  import os
19    import copy
20    
21  from wxPython.wx import *  import wx
 from wxPython.wx import __version__ as wxPython_version  
   
 from wxPython.lib.dialogs import wxMultipleChoiceDialog  
22    
23  import Thuban  import Thuban
 import Thuban.version  
24    
25  from Thuban import _  from Thuban import _
26    from Thuban.Model.messages import TITLE_CHANGED, LAYER_PROJECTION_CHANGED, \
27         MAP_PROJECTION_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED
28    
29  from Thuban.Model.session import create_empty_session  from Thuban.Model.session import create_empty_session
30  from Thuban.Model.layer import Layer, RasterLayer  from Thuban.Model.layer import Layer, RasterLayer
31    from Thuban.Model.postgisdb import PostGISShapeStore, has_postgis_support
32    from wx.lib.dialogs import MultipleChoiceDialog
33    
34  import view  import view
35  import tree  import tree
36  import tableview, identifyview  import tableview, identifyview
 from Thuban.UI.classifier import Classifier  
37  import legend  import legend
38  from menu import Menu  from menu import Menu
39    
40  from context import Context  from context import Context
41  from command import registry, Command, ToolCommand  from command import registry, Command, ToolCommand
42  from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION  from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION, \
43         MAP_REPLACED
44    from about import About
45    
46  from Thuban.UI.dock import DockFrame  from Thuban.UI.dock import DockFrame
47  from Thuban.UI.join import JoinDialog  from Thuban.UI.join import JoinDialog
48    from Thuban.UI.dbdialog import DBFrame, DBDialog, ChooseDBTableDialog
49  import resource  import resource
50    import Thuban.Model.resource
51    
52  import projdialog  import projdialog
53    
54    from Thuban.UI.classifier import Classifier
55    from Thuban.UI.rasterlayerproperties import RasterLayerProperties
56    from Thuban.Model.layer import RasterLayer
57    
58    from Thuban.Lib.classmapper import ClassMapper
59    
60    layer_properties_dialogs = ClassMapper()
61    layer_properties_dialogs.add(RasterLayer, RasterLayerProperties)
62    layer_properties_dialogs.add(Layer, Classifier)
63    
64  class MainWindow(DockFrame):  class MainWindow(DockFrame):
65    
# Line 58  class MainWindow(DockFrame): Line 69  class MainWindow(DockFrame):
69      # actually come from. This delegation is implemented in the      # actually come from. This delegation is implemented in the
70      # Subscribe and unsubscribed methods      # Subscribe and unsubscribed methods
71      delegated_messages = {LAYER_SELECTED: "canvas",      delegated_messages = {LAYER_SELECTED: "canvas",
72                            SHAPES_SELECTED: "canvas"}                            SHAPES_SELECTED: "canvas",
73                              MAP_REPLACED: "canvas"}
74    
75      # Methods delegated to some instance variables. The delegation is      # Methods delegated to some instance variables. The delegation is
76      # implemented in the __getattr__ method.      # implemented in the __getattr__ method.
77      delegated_methods = {"SelectLayer": "canvas",      delegated_methods = {"SelectLayer": "canvas",
78                           "SelectShapes": "canvas",                           "SelectShapes": "canvas",
79                             "SelectedLayer": "canvas",
80                           "SelectedShapes": "canvas",                           "SelectedShapes": "canvas",
81                           }                           }
82    
83        # Messages from the canvas that may require a status bar update.
84        # The update_status_bar method will be subscribed to these messages.
85        update_status_bar_messages = (VIEW_POSITION, LAYER_PROJECTION_CHANGED,
86                                      MAP_PROJECTION_CHANGED, MAP_LAYERS_ADDED,
87                                      MAP_LAYERS_REMOVED)
88    
89      def __init__(self, parent, ID, title, application, interactor,      def __init__(self, parent, ID, title, application, interactor,
90                   initial_message = None, size = wxSize(-1, -1)):                   initial_message = None, size = wx.Size(-1, -1)):
91          DockFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)          DockFrame.__init__(self, parent, ID, title, wx.DefaultPosition, size)
92          #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)          #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
93    
94          self.application = application          self.application = application
# Line 93  class MainWindow(DockFrame): Line 112  class MainWindow(DockFrame):
112    
113          # Create the map canvas          # Create the map canvas
114          canvas = view.MapCanvas(self, -1)          canvas = view.MapCanvas(self, -1)
         canvas.Subscribe(VIEW_POSITION, self.view_position_changed)  
115          canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)          canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
116          self.canvas = canvas          self.canvas = canvas
117            self.canvas.Subscribe(TITLE_CHANGED, self.title_changed)
118    
119            for channel in self.update_status_bar_messages:
120                self.canvas.Subscribe(channel, self.update_status_bar)
121    
122          self.SetMainWindow(self.canvas)          self.SetMainWindow(self.canvas)
123    
# Line 103  class MainWindow(DockFrame): Line 125  class MainWindow(DockFrame):
125    
126          self.init_dialogs()          self.init_dialogs()
127    
128          EVT_CLOSE(self, self.OnClose)          self.ShowLegend()
129    
130            self.Bind(wx.EVT_CLOSE, self.OnClose)
131    
132      def Subscribe(self, channel, *args):      def Subscribe(self, channel, *args):
133          """Subscribe a function to a message channel.          """Subscribe a function to a message channel.
# Line 125  class MainWindow(DockFrame): Line 149  class MainWindow(DockFrame):
149          """          """
150          if channel in self.delegated_messages:          if channel in self.delegated_messages:
151              object = getattr(self, self.delegated_messages[channel])              object = getattr(self, self.delegated_messages[channel])
152              object.Unsubscribe(channel, *args)              try:
153                    object.Unsubscribe(channel, *args)
154                except wx.PyDeadObjectError:
155                    # The object was a wxObject and has already been
156                    # destroyed. Hopefully it has unsubscribed all its
157                    # subscribers already so that it's OK if we do nothing
158                    # here
159                    pass
160    
161      def __getattr__(self, attr):      def __getattr__(self, attr):
162          """If attr is one of the delegated methods return that method          """If attr is one of the delegated methods return that method
# Line 159  class MainWindow(DockFrame): Line 190  class MainWindow(DockFrame):
190          """Bind the necessary events for the given command and ID"""          """Bind the necessary events for the given command and ID"""
191          if not self.events_bound.has_key(ID):          if not self.events_bound.has_key(ID):
192              # the events haven't been bound yet              # the events haven't been bound yet
193              EVT_MENU(self, ID, self.invoke_command)              self.Bind(wx.EVT_MENU, self.invoke_command, id=ID)
194              if command.IsDynamic():              if command.IsDynamic():
195                  EVT_UPDATE_UI(self, ID, self.update_command_ui)                  self.Bind(wx.EVT_UPDATE_UI, self.update_command_ui, id=ID)
196    
197      def build_menu_bar(self, menudesc):      def build_menu_bar(self, menudesc):
198          """Build and return the menu bar from the menu description"""          """Build and return the menu bar from the menu description"""
199          menu_bar = wxMenuBar()          menu_bar = wx.MenuBar()
200    
201          for item in menudesc.items:          for item in menudesc.items:
202              # here the items must all be Menu instances themselves              # here the items must all be Menu instances themselves
# Line 175  class MainWindow(DockFrame): Line 206  class MainWindow(DockFrame):
206    
207      def build_menu(self, menudesc):      def build_menu(self, menudesc):
208          """Return a wxMenu built from the menu description menudesc"""          """Return a wxMenu built from the menu description menudesc"""
209          wxmenu = wxMenu()          wxmenu = wx.Menu()
210          last = None          last = None
211          for item in menudesc.items:          for item in menudesc.items:
212              if item is None:              if item is None:
# Line 185  class MainWindow(DockFrame): Line 216  class MainWindow(DockFrame):
216                      wxmenu.AppendSeparator()                      wxmenu.AppendSeparator()
217              elif isinstance(item, Menu):              elif isinstance(item, Menu):
218                  # a submenu                  # a submenu
219                  wxmenu.AppendMenu(wxNewId(), item.title, self.build_menu(item))                  wxmenu.AppendMenu(wx.NewId(), item.title, self.build_menu(item))
220              else:              else:
221                  # must the name the name of a command                  # must the name the name of a command
222                  self.add_menu_command(wxmenu, item)                  self.add_menu_command(wxmenu, item)
# Line 198  class MainWindow(DockFrame): Line 229  class MainWindow(DockFrame):
229          The parameter should be an instance of the Menu class but it          The parameter should be an instance of the Menu class but it
230          should not contain submenus.          should not contain submenus.
231          """          """
232          toolbar = self.CreateToolBar(wxTB_3DBUTTONS)          toolbar = self.CreateToolBar(wx.TB_3DBUTTONS)
233    
234          # set the size of the tools' bitmaps. Not needed on wxGTK, but          # set the size of the tools' bitmaps. Not needed on wxGTK, but
235          # on Windows, although it doesn't work very well there. It seems          # on Windows, although it doesn't work very well there. It seems
236          # that only 16x16 icons are really supported on windows.          # that only 16x16 icons are really supported on windows.
237          # We probably shouldn't hardwire the bitmap size here.          # We probably shouldn't hardwire the bitmap size here.
238          toolbar.SetToolBitmapSize(wxSize(24, 24))          toolbar.SetToolBitmapSize(wx.Size(24, 24))
239    
240          for item in toolbardesc.items:          for item in toolbardesc.items:
241              if item is None:              if item is None:
# Line 245  class MainWindow(DockFrame): Line 276  class MainWindow(DockFrame):
276              command = registry.Command(name)              command = registry.Command(name)
277              if command is not None:              if command is not None:
278                  ID = self.get_id(name)                  ID = self.get_id(name)
279                  bitmap = resource.GetBitmapResource(command.Icon(),                  bitmap = resource.GetBitmapResource(command.Icon(),
280                                                      wxBITMAP_TYPE_XPM)                                                      wx.BITMAP_TYPE_XPM)
281                  toolbar.AddTool(ID, bitmap,                  toolbar.AddTool(ID, bitmap,
282                                  shortHelpString = command.HelpText(),                                  shortHelpString = command.HelpText(),
283                                  isToggle = command.IsCheckCommand())                                  isToggle = command.IsCheckCommand())
# Line 286  class MainWindow(DockFrame): Line 317  class MainWindow(DockFrame):
317              if command.IsCheckCommand():              if command.IsCheckCommand():
318                      event.Check(command.Checked(context))                      event.Check(command.Checked(context))
319    
320      def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):      def RunMessageBox(self, title, text, flags = wx.OK | wx.ICON_INFORMATION):
321          """Run a modal message box with the given text, title and flags          """Run a modal message box with the given text, title and flags
322          and return the result"""          and return the result"""
323          dlg = wxMessageDialog(self, text, title, flags)          dlg = wx.MessageDialog(self, text, title, flags)
324          dlg.CenterOnParent()          dlg.CenterOnParent()
325          result = dlg.ShowModal()          result = dlg.ShowModal()
326          dlg.Destroy()          dlg.Destroy()
# Line 316  class MainWindow(DockFrame): Line 347  class MainWindow(DockFrame):
347      def get_open_dialog(self, name):      def get_open_dialog(self, name):
348          return self.dialogs.get(name)          return self.dialogs.get(name)
349    
350      def view_position_changed(self):      def update_status_bar(self, *args):
351            """Handler for a bunch of messages that may require a status bar update
352    
353            Currently this handles the canvas' VIEW_POSITION_CHANGED
354            messages as well as several messages about changes in the map
355            which may affect whether and how projections are used.
356    
357            These messages affect the text in the status bar in the following way:
358    
359            When VIEW_POSITION_CHANGED messages are sent and the mouse is
360            actually in the canvas window, display the current mouse
361            coordinates as defined by the canvas' CurrentPosition method.
362    
363            If there is no current position to show, check whether there is
364            a potential problem with the map and layer projections and
365            display a message about it.  Otherwise the status bar will
366            become empty.
367    
368            The text is displayed in the status bar using the
369            set_position_text method.
370            """
371            # Implementation note: We do not really have to know which
372            # message was sent.  We can simply call the canvas'
373            # CurrentPosition method and if that returns a tuple, it was a
374            # VIEW_POSITION_CHANGED message and we have to display it.
375            # Otherwise it was a VIEW_POSITION_CHANGED message where the
376            # mouse has left the canvas or it was a message about a change
377            # to the map, in which case we check the projections.
378            #
379            # When changing this method, keep in mind that the
380            # VIEW_POSITION_CHANGED message are sent for every mouse move in
381            # the canvas window, that is they happen very often, so the path
382            # taken in that case has to be fast.
383            text = ""
384          pos = self.canvas.CurrentPosition()          pos = self.canvas.CurrentPosition()
385          if pos is not None:          if pos is not None:
386              text = "(%10.10g, %10.10g)" % pos              text = "(%10.10g, %10.10g)" % pos
387          else:          else:
388              text = ""              for layer in self.canvas.Map().Layers():
389                    bbox = layer.LatLongBoundingBox()
390                    if bbox:
391                        left, bottom, right, top = bbox
392                        if not (-180 <= left <= 180 and
393                                -180 <= right <= 180 and
394                                -90 <= top <= 90 and
395                                -90 <= bottom <= 90):
396                            text = _("Select layer '%s' and pick a projection "
397                                     "using Layer/Projection...") % layer.title
398                            break
399    
400          self.set_position_text(text)          self.set_position_text(text)
401    
402      def set_position_text(self, text):      def set_position_text(self, text):
403          """Set the statusbar text showing the current position.          """Set the statusbar text to that created by update_status_bar
404    
405          By default the text is shown in field 0 of the status bar.          By default the text is shown in field 0 of the status bar.
406          Override this method in derived classes to put it into a          Override this method in derived classes to put it into a
407          different field of the statusbar.          different field of the statusbar.
408    
409            For historical reasons this method is called set_position_text
410            because at first the text was always either the current position
411            or the empty string.  Now it can contain other messages as well.
412            The method will be renamed at one point.
413          """          """
414            # Note: If this method is renamed we should perhaps think about
415            # some backwards compatibility measures for projects like
416            # GREAT-ER which override this method.
417          self.SetStatusText(text)          self.SetStatusText(text)
418    
419        def OpenOrRaiseDialog(self, name, dialog_class, *args, **kw):
420            """
421            Open or raise a dialog.
422    
423            If a dialog with the denoted name does already exist it is
424            raised.  Otherwise a new dialog, an instance of dialog_class,
425            is created, inserted into the main list and displayed.
426            """
427            dialog = self.get_open_dialog(name)
428    
429            if dialog is None:
430                dialog = dialog_class(self, name, *args, **kw)
431                self.add_dialog(name, dialog)
432                dialog.Show(True)
433            else:
434                dialog.Raise()
435    
436      def save_modified_session(self, can_veto = 1):      def save_modified_session(self, can_veto = 1):
437          """If the current session has been modified, ask the user          """If the current session has been modified, ask the user
438          whether to save it and do so if requested. Return the outcome of          whether to save it and do so if requested. Return the outcome of
# Line 343  class MainWindow(DockFrame): Line 443  class MainWindow(DockFrame):
443          a cancel button, otherwise not.          a cancel button, otherwise not.
444          """          """
445          if self.application.session.WasModified():          if self.application.session.WasModified():
446              flags = wxYES_NO | wxICON_QUESTION              flags = wx.YES_NO | wx.ICON_QUESTION
447              if can_veto:              if can_veto:
448                  flags = flags | wxCANCEL                  flags = flags | wx.CANCEL
449              result = self.RunMessageBox(_("Exit"),              result = self.RunMessageBox(_("Exit"),
450                                          _("The session has been modified."                                          _("The session has been modified."
451                                           " Do you want to save it?"),                                           " Do you want to save it?"),
452                                          flags)                                          flags)
453              if result == wxID_YES:              if result == wx.ID_YES:
454                  self.SaveSession()                  self.SaveSession()
455          else:          else:
456              result = wxID_NO              result = wx.ID_NO
457          return result          return result
458    
     def prepare_new_session(self):  
         for d in self.dialogs.values():  
             if not isinstance(d, tree.SessionTreeView):  
                 d.Close()  
   
459      def NewSession(self):      def NewSession(self):
460          if self.save_modified_session() != wxID_CANCEL:          if self.save_modified_session() != wx.ID_CANCEL:
             self.prepare_new_session()  
461              self.application.SetSession(create_empty_session())              self.application.SetSession(create_empty_session())
462    
463      def OpenSession(self):      def OpenSession(self):
464          if self.save_modified_session() != wxID_CANCEL:          if self.save_modified_session() != wx.ID_CANCEL:
465              dlg = wxFileDialog(self, _("Open Session"), ".", "",              dlg = wx.FileDialog(self, _("Open Session"),
466                                 "Thuban Session File (*.thuban)|*.thuban",                                 self.application.Path("data"), "",
467                                 wxOPEN)                                 "Thuban Session File (*.thuban)|*.thuban",
468              if dlg.ShowModal() == wxID_OK:                                 wx.OPEN)
469                  self.prepare_new_session()              if dlg.ShowModal() == wx.ID_OK:
470                  self.application.OpenSession(dlg.GetPath())                  self.application.OpenSession(dlg.GetPath(),
471                                                 self.run_db_param_dialog)
472                    self.application.SetPath("data", dlg.GetPath())
473              dlg.Destroy()              dlg.Destroy()
474    
475        def run_db_param_dialog(self, parameters, message):
476            dlg = DBDialog(self, _("DB Connection Parameters"), parameters,
477                           message)
478            return dlg.RunDialog()
479    
480      def SaveSession(self):      def SaveSession(self):
481          if self.application.session.filename == None:          if self.application.session.filename == None:
482              self.SaveSessionAs()              self.SaveSessionAs()
# Line 383  class MainWindow(DockFrame): Line 484  class MainWindow(DockFrame):
484              self.application.SaveSession()              self.application.SaveSession()
485    
486      def SaveSessionAs(self):      def SaveSessionAs(self):
487          dlg = wxFileDialog(self, _("Save Session As"), ".", "",          dlg = wx.FileDialog(self, _("Save Session As"),
488                             "Thuban Session File (*.thuban)|*.thuban",                             self.application.Path("data"), "",
489                             wxSAVE|wxOVERWRITE_PROMPT)                             "Thuban Session File (*.thuban)|*.thuban",
490          if dlg.ShowModal() == wxID_OK:                             wx.SAVE|wx.OVERWRITE_PROMPT)
491            if dlg.ShowModal() == wx.ID_OK:
492              self.application.session.SetFilename(dlg.GetPath())              self.application.session.SetFilename(dlg.GetPath())
493              self.application.SaveSession()              self.application.SaveSession()
494                self.application.SetPath("data",dlg.GetPath())
495          dlg.Destroy()          dlg.Destroy()
496    
497      def Exit(self):      def Exit(self):
# Line 396  class MainWindow(DockFrame): Line 499  class MainWindow(DockFrame):
499    
500      def OnClose(self, event):      def OnClose(self, event):
501          result = self.save_modified_session(can_veto = event.CanVeto())          result = self.save_modified_session(can_veto = event.CanVeto())
502          if result == wxID_CANCEL:          if result == wx.ID_CANCEL:
503              event.Veto()              event.Veto()
504          else:          else:
505              # FIXME: it would be better to tie the unsubscription to              # FIXME: it would be better to tie the unsubscription to
506              # wx's destroy event, but that isn't implemented for wxGTK              # wx's destroy event, but that isn't implemented for wxGTK
507              # yet.              # yet.
508              self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)              for channel in self.update_status_bar_messages:
509                    self.canvas.Unsubscribe(channel, self.update_status_bar)
510    
511              DockFrame.OnClose(self, event)              DockFrame.OnClose(self, event)
512              for dlg in self.dialogs.values():              for dlg in self.dialogs.values():
513                  dlg.Destroy()                  dlg.Destroy()
# Line 411  class MainWindow(DockFrame): Line 516  class MainWindow(DockFrame):
516    
517      def SetMap(self, map):      def SetMap(self, map):
518          self.canvas.SetMap(map)          self.canvas.SetMap(map)
519          self.__SetTitle(map.Title())          self.update_title()
520    
521          dialog = self.FindRegisteredDock("legend")          dialog = self.FindRegisteredDock("legend")
522          if dialog is not None:          if dialog is not None:
# Line 438  class MainWindow(DockFrame): Line 543  class MainWindow(DockFrame):
543          return self.get_open_dialog("session_tree") is not None          return self.get_open_dialog("session_tree") is not None
544    
545      def About(self):      def About(self):
546          self.RunMessageBox(_("About"),          dlg = About(self)
547                             _("Thuban %s\n"          dlg.ShowModal()
548                              #"Build Date: %s\n"          dlg.Destroy()
                             "using:\n"  
                             "  %s\n"  
                             "  %s\n\n"  
                             "Thuban is a program for\n"  
                             "exploring geographic data.\n"  
                             "Copyright (C) 2001-2003 Intevation GmbH.\n"  
                             "Thuban is licensed under the GNU GPL"  
                             % (Thuban.version.longversion,  
                                "wxPython %s" % wxPython_version,  
                                "Python %d.%d.%d" % sys.version_info[:3]  
                               )),  
 #                           % __ThubanVersion__), #__BuildDate__)),  
                            wxOK | wxICON_INFORMATION)  
549    
550      def AddLayer(self):      def DatabaseManagement(self):
551          dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",          name = "dbmanagement"
552                             wxOPEN)          dialog = self.get_open_dialog(name)
553          if dlg.ShowModal() == wxID_OK:          if dialog is None:
             filename = dlg.GetPath()  
             title = os.path.splitext(os.path.basename(filename))[0]  
554              map = self.canvas.Map()              map = self.canvas.Map()
555              has_layers = map.HasLayers()              dialog = DBFrame(self, name, self.application.Session())
556              try:              self.add_dialog(name, dialog)
557                  store = self.application.Session().OpenShapefile(filename)              dialog.Show()
558              except IOError:          dialog.Raise()
559                  # the layer couldn't be opened  
560                  self.RunMessageBox(_("Add Layer"),      def AddLayer(self):
561                                     _("Can't open the file '%s'.") % filename)          dlg = wx.FileDialog(self, _("Select one or more data files"),
562              else:                             self.application.Path("data"), "",
563                  layer = Layer(title, store)                             _("Shapefiles (*.shp)") + "|*.shp;*.SHP|" +
564                  map.AddLayer(layer)                             _("All Files (*.*)") + "|*.*",
565                  if not has_layers:                             wx.OPEN | wx.MULTIPLE)
566                      # if we're adding a layer to an empty map, fit the          if dlg.ShowModal() == wx.ID_OK:
567                      # new map to the window              filenames = dlg.GetPaths()
568                      self.canvas.FitMapToWindow()              for filename in filenames:
569                    title = os.path.splitext(os.path.basename(filename))[0]
570                    map = self.canvas.Map()
571                    has_layers = map.HasLayers()
572                    try:
573                        store = self.application.Session().OpenShapefile(filename)
574                    except IOError:
575                        # the layer couldn't be opened
576                        self.RunMessageBox(_("Add Layer"),
577                                           _("Can't open the file '%s'.")%filename)
578                    else:
579                        layer = Layer(title, store)
580                        map.AddLayer(layer)
581                        if not has_layers:
582                            # if we're adding a layer to an empty map, fit the
583                            # new map to the window
584                            self.canvas.FitMapToWindow()
585                        self.application.SetPath("data",filename)
586          dlg.Destroy()          dlg.Destroy()
587    
588      def AddRasterLayer(self):      def AddRasterLayer(self):
589          dlg = wxFileDialog(self, _("Select an image file"), ".", "", "*.*",          dlg = wx.FileDialog(self, _("Select an image file"),
590                             wxOPEN)                             self.application.Path("data"), "", "*.*",
591          if dlg.ShowModal() == wxID_OK:                             wx.OPEN)
592            if dlg.ShowModal() == wx.ID_OK:
593              filename = dlg.GetPath()              filename = dlg.GetPath()
594              title = os.path.splitext(os.path.basename(filename))[0]              title = os.path.splitext(os.path.basename(filename))[0]
595              map = self.canvas.Map()              map = self.canvas.Map()
# Line 498  class MainWindow(DockFrame): Line 606  class MainWindow(DockFrame):
606                      # if we're adding a layer to an empty map, fit the                      # if we're adding a layer to an empty map, fit the
607                      # new map to the window                      # new map to the window
608                      self.canvas.FitMapToWindow()                      self.canvas.FitMapToWindow()
609                    self.application.SetPath("data", filename)
610            dlg.Destroy()
611    
612        def AddDBLayer(self):
613            """Add a layer read from a database"""
614            session = self.application.Session()
615            dlg = ChooseDBTableDialog(self, self.application.Session())
616    
617            if dlg.ShowModal() == wx.ID_OK:
618                dbconn, dbtable, id_column, geo_column = dlg.GetTable()
619                try:
620                    title = str(dbtable)
621    
622                    # Chose the correct Interface for the database type
623                    store = session.OpenDBShapeStore(dbconn, dbtable,
624                                                     id_column = id_column,
625                                                     geometry_column = geo_column)
626                    layer = Layer(title, store)
627                except:
628                    # Some error occured while initializing the layer
629                    self.RunMessageBox(_("Add Layer from database"),
630                                       _("Can't open the database table '%s'")
631                                       % dbtable)
632                    return
633    
634                map = self.canvas.Map()
635    
636                has_layers = map.HasLayers()
637                map.AddLayer(layer)
638                if not has_layers:
639                    self.canvas.FitMapToWindow()
640    
641          dlg.Destroy()          dlg.Destroy()
642    
643      def RemoveLayer(self):      def RemoveLayer(self):
# Line 518  class MainWindow(DockFrame): Line 658  class MainWindow(DockFrame):
658              return self.canvas.Map().CanRemoveLayer(layer)              return self.canvas.Map().CanRemoveLayer(layer)
659          return False          return False
660    
661        def LayerToTop(self):
662            layer = self.current_layer()
663            if layer is not None:
664                self.canvas.Map().MoveLayerToTop(layer)
665    
666      def RaiseLayer(self):      def RaiseLayer(self):
667          layer = self.current_layer()          layer = self.current_layer()
668          if layer is not None:          if layer is not None:
# Line 528  class MainWindow(DockFrame): Line 673  class MainWindow(DockFrame):
673          if layer is not None:          if layer is not None:
674              self.canvas.Map().LowerLayer(layer)              self.canvas.Map().LowerLayer(layer)
675    
676        def LayerToBottom(self):
677            layer = self.current_layer()
678            if layer is not None:
679                self.canvas.Map().MoveLayerToBottom(layer)
680    
681      def current_layer(self):      def current_layer(self):
682          """Return the currently selected layer.          """Return the currently selected layer.
683    
# Line 539  class MainWindow(DockFrame): Line 689  class MainWindow(DockFrame):
689          """Return true if a layer is currently selected"""          """Return true if a layer is currently selected"""
690          return self.canvas.HasSelectedLayer()          return self.canvas.HasSelectedLayer()
691    
692        def has_selected_shape_layer(self):
693            """Return true if a shape layer is currently selected"""
694            return isinstance(self.current_layer(), Layer)
695    
696      def has_selected_shapes(self):      def has_selected_shapes(self):
697          """Return true if a shape is currently selected"""          """Return true if a shape is currently selected"""
698          return self.canvas.HasSelectedShapes()          return self.canvas.HasSelectedShapes()
# Line 546  class MainWindow(DockFrame): Line 700  class MainWindow(DockFrame):
700      def HideLayer(self):      def HideLayer(self):
701          layer = self.current_layer()          layer = self.current_layer()
702          if layer is not None:          if layer is not None:
703              layer.SetVisible(0)              layer.SetVisible(False)
704            
705      def ShowLayer(self):      def ShowLayer(self):
706          layer = self.current_layer()          layer = self.current_layer()
707          if layer is not None:          if layer is not None:
708              layer.SetVisible(1)              layer.SetVisible(True)
709    
710        def ToggleLayerVisibility(self):
711            layer = self.current_layer()
712            layer.SetVisible(not layer.Visible())
713    
714        def DuplicateLayer(self):
715            """Ceate a new layer above the selected layer with the same shapestore
716            """
717            layer = self.current_layer()
718            if layer is not None and hasattr(layer, "ShapeStore"):
719                new_layer = Layer(_("Copy of `%s'") % layer.Title(),
720                                  layer.ShapeStore(),
721                                  projection = layer.GetProjection())
722                new_classification = copy.deepcopy(layer.GetClassification())
723                new_layer.SetClassificationColumn(
724                        layer.GetClassificationColumn())
725                new_layer.SetClassification(new_classification)
726                self.Map().AddLayer(new_layer)
727    
728        def CanDuplicateLayer(self):
729            """Return whether the DuplicateLayer method can create a duplicate"""
730            layer = self.current_layer()
731            return layer is not None and hasattr(layer, "ShapeStore")
732    
733      def LayerShowTable(self):      def LayerShowTable(self):
734            """
735            Present a TableView Window for the current layer.
736            In case the window is already open, bring it to the front.
737            In case, there is no active layer, do nothing.
738            In case, the layer has no ShapeStore, do nothing.
739            """
740          layer = self.current_layer()          layer = self.current_layer()
741          if layer is not None:          if layer is not None:
742              table = layer.table              if not hasattr(layer, "ShapeStore"):
743                    return
744                table = layer.ShapeStore().Table()
745              name = "table_view" + str(id(table))              name = "table_view" + str(id(table))
746              dialog = self.get_open_dialog(name)              dialog = self.get_open_dialog(name)
747              if dialog is None:              if dialog is None:
# Line 566  class MainWindow(DockFrame): Line 751  class MainWindow(DockFrame):
751                  self.add_dialog(name, dialog)                  self.add_dialog(name, dialog)
752                  dialog.Show(True)                  dialog.Show(True)
753              else:              else:
754                  # FIXME: bring dialog to front here                  dialog.Raise()
                 pass  
755    
756      def MapProjection(self):      def MapProjection(self):
757    
# Line 576  class MainWindow(DockFrame): Line 760  class MainWindow(DockFrame):
760    
761          if dialog is None:          if dialog is None:
762              map = self.canvas.Map()              map = self.canvas.Map()
763              dialog = projdialog.ProjFrame(self, name,              dialog = projdialog.ProjFrame(self, name,
764                       _("Map Projection: %s") % map.Title(), map)                       _("Map Projection: %s") % map.Title(), map)
765              self.add_dialog(name, dialog)              self.add_dialog(name, dialog)
766              dialog.Show()              dialog.Show()
# Line 591  class MainWindow(DockFrame): Line 775  class MainWindow(DockFrame):
775    
776          if dialog is None:          if dialog is None:
777              map = self.canvas.Map()              map = self.canvas.Map()
778              dialog = projdialog.ProjFrame(self, name,              dialog = projdialog.ProjFrame(self, name,
779                       _("Layer Projection: %s") % layer.Title(), layer)                       _("Layer Projection: %s") % layer.Title(), layer)
780              self.add_dialog(name, dialog)              self.add_dialog(name, dialog)
781              dialog.Show()              dialog.Show()
# Line 609  class MainWindow(DockFrame): Line 793  class MainWindow(DockFrame):
793          self.OpenLayerProperties(layer)          self.OpenLayerProperties(layer)
794    
795      def OpenLayerProperties(self, layer, group = None):      def OpenLayerProperties(self, layer, group = None):
796          name = "layer_properties" + str(id(layer))          """
797          dialog = self.get_open_dialog(name)          Open or raise the properties dialog.
798    
799          if dialog is None:          This method opens or raises the properties dialog for the
800              dialog = Classifier(self, name, layer, group)          currently selected layer if one is defined for this layer
801              self.add_dialog(name, dialog)          type.
802              dialog.Show()          """
803          dialog.Raise()          dialog_class = layer_properties_dialogs.get(layer)
804    
805            if dialog_class is not None:
806                name = "layer_properties" + str(id(layer))
807                self.OpenOrRaiseDialog(name, dialog_class, layer, group = group)
808    
809      def LayerJoinTable(self):      def LayerJoinTable(self):
810          print "LayerJoinTable: Not implemented."          layer = self.canvas.SelectedLayer()
811            if layer is not None:
812                dlg = JoinDialog(self, _("Join Layer with Table"),
813                                 self.application.session,
814                                 layer = layer)
815                dlg.ShowModal()
816    
817      def LayerUnjoinTable(self):      def LayerUnjoinTable(self):
818          print "LayerUnjoinTable: Not implemented."          layer = self.canvas.SelectedLayer()
819            if layer is not None:
820                orig_store = layer.ShapeStore().OrigShapeStore()
821                if orig_store:
822                    layer.SetShapeStore(orig_store)
823    
824      def ShowLegend(self):      def ShowLegend(self):
825          if not self.LegendShown():          if not self.LegendShown():
# Line 634  class MainWindow(DockFrame): Line 831  class MainWindow(DockFrame):
831          dialog = self.FindRegisteredDock(name)          dialog = self.FindRegisteredDock(name)
832    
833          if dialog is None:          if dialog is None:
834              dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)              dialog = self.CreateDock(name, -1, _("Legend"), wx.LAYOUT_LEFT)
835              legend.LegendPanel(dialog, None, self)              legend.LegendPanel(dialog, None, self)
836              dialog.Dock()              dialog.Dock()
837              dialog.GetPanel().SetMap(self.Map())              dialog.GetPanel().SetMap(self.Map())
# Line 644  class MainWindow(DockFrame): Line 841  class MainWindow(DockFrame):
841    
842      def LegendShown(self):      def LegendShown(self):
843          """Return true iff the legend is currently open"""          """Return true iff the legend is currently open"""
844          dialog = self.FindRegisteredDock("legend")          dialog = self.FindRegisteredDock("legend")
845          return dialog is not None and dialog.IsShown()          return dialog is not None and dialog.IsShown()
846    
847      def TableOpen(self):      def TableOpen(self):
848          dlg = wxFileDialog(self, _("Open Table"), ".", "",          dlg = wx.FileDialog(self, _("Open Table"),
849                             _("DBF Files (*.dbf)") + "|*.dbf|" +                             self.application.Path("data"), "",
850                               _("DBF Files (*.dbf)") + "|*.dbf|" +
851                             #_("CSV Files (*.csv)") + "|*.csv|" +                             #_("CSV Files (*.csv)") + "|*.csv|" +
852                             _("All Files (*.*)") + "|*.*",                             _("All Files (*.*)") + "|*.*",
853                             wxOPEN)                             wx.OPEN)
854          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wx.ID_OK:
855              filename = dlg.GetPath()              filename = dlg.GetPath()
856              dlg.Destroy()              dlg.Destroy()
857              try:              try:
# Line 664  class MainWindow(DockFrame): Line 862  class MainWindow(DockFrame):
862                                     _("Can't open the file '%s'.") % filename)                                     _("Can't open the file '%s'.") % filename)
863              else:              else:
864                  self.ShowTableView(table)                  self.ShowTableView(table)
865                    self.application.SetPath("data",filename)
866    
867      def TableClose(self):      def TableClose(self):
868          tables = self.application.session.UnreferencedTables()          tables = self.application.session.UnreferencedTables()
869    
870          dlg = wxMultipleChoiceDialog(self, _("Pick the tables to close:"),          lst = [(t.Title(), t) for t in tables]
871                                       _("Close Table"),          lst.sort()
872                                       [t.Title() for t in tables],          titles = [i[0] for i in lst]
873                                       size = (400, 300), style=wxRESIZE_BORDER)          dlg = MultipleChoiceDialog(self, _("Pick the tables to close:"),
874          if dlg.ShowModal() == wxID_OK:                                       _("Close Table"), titles,
875                                         size = (400, 300),
876                                         style = wx.DEFAULT_DIALOG_STYLE |
877                                                 wx.RESIZE_BORDER)
878            if dlg.ShowModal() == wx.ID_OK:
879              for i in dlg.GetValue():              for i in dlg.GetValue():
880                  self.application.session.RemoveTable(tables[i])                  self.application.session.RemoveTable(lst[i][1])
881    
882    
883      def TableShow(self):      def TableShow(self):
# Line 685  class MainWindow(DockFrame): Line 888  class MainWindow(DockFrame):
888          """          """
889          tables = self.application.session.Tables()          tables = self.application.session.Tables()
890    
891          dlg = wxMultipleChoiceDialog(self, _("Pick the table to show:"),          lst = [(t.Title(), t) for t in tables]
892                                       _("Show Table"),          lst.sort()
893                                       [t.Title() for t in tables],          titles = [i[0] for i in lst]
894                                       size = (400,300), style = wxRESIZE_BORDER)          dlg = MultipleChoiceDialog(self, _("Pick the table to show:"),
895          if (dlg.ShowModal() == wxID_OK):                                       _("Show Table"), titles,
896                                         size = (400,300),
897                                         style = wx.DEFAULT_DIALOG_STYLE |
898                                                 wx.RESIZE_BORDER)
899            if (dlg.ShowModal() == wx.ID_OK):
900              for i in dlg.GetValue():              for i in dlg.GetValue():
901                  # XXX: if the table belongs to a layer, open a                  # XXX: if the table belongs to a layer, open a
902                  # LayerTableFrame instead of QueryTableFrame                  # LayerTableFrame instead of QueryTableFrame
903                  self.ShowTableView(tables[i])                  self.ShowTableView(lst[i][1])
904    
905      def TableJoin(self):      def TableJoin(self):
906          dlg = JoinDialog(self, _("Join Tables"), self.application.session)          dlg = JoinDialog(self, _("Join Tables"), self.application.session)
# Line 709  class MainWindow(DockFrame): Line 916  class MainWindow(DockFrame):
916                                                 table)                                                 table)
917              self.add_dialog(name, dialog)              self.add_dialog(name, dialog)
918              dialog.Show(True)              dialog.Show(True)
919          # FIXME: else bring dialog to front          dialog.Raise()
920    
921        def TableRename(self):
922            """Let the user rename a table"""
923    
924            # First, let the user select a table
925            tables = self.application.session.Tables()
926            lst = [(t.Title(), t) for t in tables]
927            lst.sort()
928            titles = [i[0] for i in lst]
929            dlg = MultipleChoiceDialog(self, _("Pick the table to rename:"),
930                                         _("Rename Table"), titles,
931                                         size = (400,300),
932                                         style = wx.DEFAULT_DIALOG_STYLE |
933                                                 wx.RESIZE_BORDER)
934            if (dlg.ShowModal() == wx.ID_OK):
935                to_rename = [lst[i][1] for i in dlg.GetValue()]
936                dlg.Destroy()
937            else:
938                to_rename = []
939    
940            # Second, let the user rename the layers
941            for table in to_rename:
942                dlg = wx.TextEntryDialog(self, _("Table Title:"), _("Rename Table"),
943                                        table.Title())
944                try:
945                    if dlg.ShowModal() == wx.ID_OK:
946                        title = dlg.GetValue()
947                        if title != "":
948                            table.SetTitle(title)
949    
950                            # Make sure the session is marked as modified.
951                            # FIXME: This should be handled automatically,
952                            # but that requires more changes to the tables
953                            # than I have time for currently.
954                            self.application.session.changed()
955                finally:
956                    dlg.Destroy()
957    
958    
959      def ZoomInTool(self):      def ZoomInTool(self):
960          self.canvas.ZoomInTool()          self.canvas.ZoomInTool()
# Line 743  class MainWindow(DockFrame): Line 988  class MainWindow(DockFrame):
988          self.canvas.Print()          self.canvas.Print()
989    
990      def RenameMap(self):      def RenameMap(self):
991          dlg = wxTextEntryDialog(self, "Map Title: ", "Rename Map",          dlg = wx.TextEntryDialog(self, _("Map Title:"), _("Rename Map"),
992                                  self.Map().Title())                                  self.Map().Title())
993          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wx.ID_OK:
994              title = dlg.GetValue()              title = dlg.GetValue()
995              if title != "":              if title != "":
996                  self.Map().SetTitle(title)                  self.Map().SetTitle(title)
                 self.__SetTitle(title)  
997    
998          dlg.Destroy()          dlg.Destroy()
999    
1000        def RenameLayer(self):
1001            """Let the user rename the currently selected layer"""
1002            layer = self.current_layer()
1003            if layer is not None:
1004                dlg = wx.TextEntryDialog(self, _("Layer Title:"), _("Rename Layer"),
1005                                        layer.Title())
1006                try:
1007                    if dlg.ShowModal() == wx.ID_OK:
1008                        title = dlg.GetValue()
1009                        if title != "":
1010                            layer.SetTitle(title)
1011                finally:
1012                    dlg.Destroy()
1013    
1014      def identify_view_on_demand(self, layer, shapes):      def identify_view_on_demand(self, layer, shapes):
1015          """Subscribed to the canvas' SHAPES_SELECTED message          """Subscribed to the canvas' SHAPES_SELECTED message
1016    
# Line 777  class MainWindow(DockFrame): Line 1035  class MainWindow(DockFrame):
1035                  # FIXME: bring dialog to front?                  # FIXME: bring dialog to front?
1036                  pass                  pass
1037    
1038      def __SetTitle(self, title):      def title_changed(self, map):
1039          self.SetTitle("Thuban - " + title)          """Subscribed to the canvas' TITLE_CHANGED messages"""
1040            self.update_title()
1041    
1042        def update_title(self):
1043            """Update the window's title according to it's current state.
1044    
1045            In this default implementation the title is 'Thuban - ' followed
1046            by the map's title or simply 'Thuban' if there is not map.
1047            Derived classes should override this method to get different
1048            titles.
1049    
1050            This method is called automatically by other methods when the
1051            title may have to change. For the methods implemented in this
1052            class this usually only means that a different map has been set
1053            or the current map's title has changed.
1054            """
1055            map = self.Map()
1056            if map is not None:
1057                title = _("Thuban - %s") % (map.Title(),)
1058            else:
1059                title = _("Thuban")
1060            self.SetTitle(title)
1061    
1062    
1063  #  #
1064  # Define all the commands available in the main window  # Define all the commands available in the main window
# Line 820  def _has_selected_layer(context): Line 1100  def _has_selected_layer(context):
1100      """Return true if a layer is selected in the context"""      """Return true if a layer is selected in the context"""
1101      return context.mainwindow.has_selected_layer()      return context.mainwindow.has_selected_layer()
1102    
1103    def _has_selected_layer_visible(context):
1104        """Return true if a layer is selected in the context which is
1105        visible."""
1106        if context.mainwindow.has_selected_layer():
1107            layer = context.mainwindow.current_layer()
1108            if layer.Visible(): return True
1109        return False
1110    
1111    def _has_selected_shape_layer(context):
1112        """Return true if a shape layer is selected in the context"""
1113        return context.mainwindow.has_selected_shape_layer()
1114    
1115  def _has_selected_shapes(context):  def _has_selected_shapes(context):
1116      """Return true if a layer is selected in the context"""      """Return true if a layer is selected in the context"""
1117      return context.mainwindow.has_selected_shapes()      return context.mainwindow.has_selected_shapes()
# Line 839  def _has_visible_map(context): Line 1131  def _has_visible_map(context):
1131      if map is not None:      if map is not None:
1132          for layer in map.Layers():          for layer in map.Layers():
1133              if layer.Visible():              if layer.Visible():
1134                  return 1                  return True
1135      return 0      return False
1136    
1137  def _has_legend_shown(context):  def _has_legend_shown(context):
1138      """Return true if the legend window is shown"""      """Return true if the legend window is shown"""
1139      return context.mainwindow.LegendShown()      return context.mainwindow.LegendShown()
1140    
1141    def _has_gdal_support(context):
1142        """Return True if the GDAL is available"""
1143        return Thuban.Model.resource.has_gdal_support()
1144    
1145    def _has_dbconnections(context):
1146        """Return whether the the session has database connections"""
1147        return context.session.HasDBConnections()
1148    
1149    def _has_postgis_support(context):
1150        return has_postgis_support()
1151    
1152    
1153  # File menu  # File menu
1154  _method_command("new_session", _("&New Session"), "NewSession")  _method_command("new_session", _("&New Session"), "NewSession",
1155  _method_command("open_session", _("&Open Session..."), "OpenSession")                  helptext = _("Start a new session"))
1156  _method_command("save_session", _("&Save Session"), "SaveSession")  _method_command("open_session", _("&Open Session..."), "OpenSession",
1157  _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs")                  helptext = _("Open a session file"))
1158    _method_command("save_session", _("&Save Session"), "SaveSession",
1159                    helptext =_("Save this session to the file it was opened from"))
1160    _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs",
1161                    helptext = _("Save this session to a new file"))
1162  _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",  _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
1163                  checked = _has_tree_window_shown)                  checked = _has_tree_window_shown,
1164                    helptext = _("Toggle on/off the session tree analysis window"))
1165  _method_command("toggle_legend", _("Legend"), "ToggleLegend",  _method_command("toggle_legend", _("Legend"), "ToggleLegend",
1166                  checked = _has_legend_shown)                  checked = _has_legend_shown,
1167  _method_command("exit", _("E&xit"), "Exit")                  helptext = _("Toggle Legend on/off"))
1168    _method_command("database_management", _("&Database Connections..."),
1169                    "DatabaseManagement",
1170                    sensitive = _has_postgis_support)
1171    _method_command("exit", _("E&xit"), "Exit",
1172                    helptext = _("Finish working with Thuban"))
1173    
1174  # Help menu  # Help menu
1175  _method_command("help_about", _("&About..."), "About")  _method_command("help_about", _("&About..."), "About",
1176                    helptext = _("Info about Thuban authors, version and modules"))
1177    
1178    
1179  # Map menu  # Map menu
1180  _method_command("map_projection", _("Pro&jection..."), "MapProjection")  _method_command("map_projection", _("Pro&jection..."), "MapProjection",
1181                    helptext = _("Set or change the map projection"))
1182    
1183  _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",  _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
1184                helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",                helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
# Line 882  _tool_command("map_label_tool", _("&Labe Line 1197  _tool_command("map_label_tool", _("&Labe
1197                helptext = _("Add/Remove labels"), icon = "label",                helptext = _("Add/Remove labels"), icon = "label",
1198                sensitive = _has_visible_map)                sensitive = _has_visible_map)
1199  _method_command("map_full_extent", _("&Full extent"), "FullExtent",  _method_command("map_full_extent", _("&Full extent"), "FullExtent",
1200                 helptext = _("Full Extent"), icon = "fullextent",                 helptext = _("Zoom to the full map extent"), icon = "fullextent",
1201                sensitive = _has_visible_map)                sensitive = _has_visible_map)
1202  _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",  _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
1203                 helptext = _("Full Layer Extent"), icon = "fulllayerextent",                  helptext = _("Zoom to the full layer extent"),
1204                sensitive = _has_selected_layer)                  icon = "fulllayerextent", sensitive = _has_selected_layer)
1205  _method_command("selected_full_extent", _("&Full selection extent"), "FullSelectionExtent",  _method_command("selected_full_extent", _("&Full selection extent"),
1206                 helptext = _("Full Selection Extent"), icon = "fullselextent",                  "FullSelectionExtent",
1207                sensitive = _has_selected_shapes)                  helptext = _("Zoom to the full selection extent"),
1208                    icon = "fullselextent", sensitive = _has_selected_shapes)
1209  _method_command("map_export", _("E&xport"), "ExportMap",  _method_command("map_export", _("E&xport"), "ExportMap",
1210                      helptext = _("Export the map to file"))                  helptext = _("Export the map to file"))
1211  _method_command("map_print", _("Prin&t"), "PrintMap",  _method_command("map_print", _("Prin&t"), "PrintMap",
1212                  helptext = _("Print the map"))                  helptext = _("Print the map"))
1213  _method_command("map_rename", _("&Rename..."), "RenameMap",  _method_command("map_rename", _("&Rename..."), "RenameMap",
1214                  helptext = _("Rename the map"))                  helptext = _("Rename the map"))
1215  _method_command("layer_add", _("&Add Layer..."), "AddLayer",  _method_command("layer_add", _("&Add Layer..."), "AddLayer",
1216                  helptext = _("Add a new layer to active map"))                  helptext = _("Add a new layer to the map"))
1217  _method_command("rasterlayer_add", _("&Add Image Layer..."), "AddRasterLayer",  _method_command("rasterlayer_add", _("&Add Image Layer..."), "AddRasterLayer",
1218                  helptext = _("Add a new image layer to active map"))                  helptext = _("Add a new image layer to the map"),
1219                    sensitive = _has_gdal_support)
1220    _method_command("layer_add_db", _("Add &Database Layer..."), "AddDBLayer",
1221                    helptext = _("Add a new database layer to active map"),
1222                    sensitive = _has_dbconnections)
1223  _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",  _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
1224                  helptext = _("Remove selected layer(s)"),                  helptext = _("Remove selected layer"),
1225                  sensitive = _can_remove_layer)                  sensitive = _can_remove_layer)
1226    
1227  # Layer menu  # Layer menu
1228  _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",  _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
1229                    sensitive = _has_selected_layer,
1230                    helptext = _("Specify projection for selected layer"))
1231    _method_command("layer_duplicate", _("&Duplicate"), "DuplicateLayer",
1232                    helptext = _("Duplicate selected layer"),
1233              sensitive = lambda context: context.mainwindow.CanDuplicateLayer())
1234    _method_command("layer_rename", _("Re&name ..."), "RenameLayer",
1235                    helptext = _("Rename selected layer"),
1236                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1237  _method_command("layer_raise", _("&Raise"), "RaiseLayer",  _method_command("layer_raise", _("&Raise"), "RaiseLayer",
1238                  helptext = _("Raise selected layer(s)"),                  helptext = _("Raise selected layer"),
1239                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1240  _method_command("layer_lower", _("&Lower"), "LowerLayer",  _method_command("layer_lower", _("&Lower"), "LowerLayer",
1241                  helptext = _("Lower selected layer(s)"),                  helptext = _("Lower selected layer"),
1242                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1243  _method_command("layer_show", _("&Show"), "ShowLayer",  _method_command("layer_show", _("&Show"), "ShowLayer",
1244                  helptext = _("Make selected layer(s) visible"),                  helptext = _("Make selected layer visible"),
1245                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1246  _method_command("layer_hide", _("&Hide"), "HideLayer",  _method_command("layer_hide", _("&Hide"), "HideLayer",
1247                  helptext = _("Make selected layer(s) unvisible"),                  helptext = _("Make selected layer unvisible"),
1248                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1249  _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",  _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
1250                  helptext = _("Show the selected layer's table"),                  helptext = _("Show the selected layer's table"),
1251                  sensitive = _has_selected_layer)                  sensitive = _has_selected_shape_layer)
1252  _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",  _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
1253                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer,
1254                    helptext = _("Edit the properties of the selected layer"))
1255  _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",  _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
1256                    sensitive = _has_selected_shape_layer,
1257                    helptext = _("Join and attach a table to the selected layer"))
1258    
1259    # further layer methods:
1260    _method_command("layer_to_top", _("&Top"), "LayerToTop",
1261                    helptext = _("Put selected layer to the top"),
1262                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1263  _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",  _method_command("layer_to_bottom", _("&Bottom"), "LayerToBottom",
1264                    helptext = _("Put selected layer to the bottom"),
1265                    sensitive = _has_selected_layer)
1266    _method_command("layer_visibility", _("&Visible"), "ToggleLayerVisibility",
1267                    checked = _has_selected_layer_visible,
1268                    helptext = _("Toggle visibility of selected layer"),
1269                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
1270    
1271    def _can_unjoin(context):
1272        """Return whether the Layer/Unjoin command can be executed.
1273    
1274        This is the case if a layer is selected and that layer has a
1275        shapestore that has an original shapestore.
1276        """
1277        layer = context.mainwindow.SelectedLayer()
1278        if layer is None:
1279            return 0
1280        getstore = getattr(layer, "ShapeStore", None)
1281        if getstore is not None:
1282            return getstore().OrigShapeStore() is not None
1283        else:
1284            return 0
1285    _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
1286                    sensitive = _can_unjoin,
1287                    helptext = _("Undo the last join operation"))
1288    
1289    
1290    def _has_tables(context):
1291        return bool(context.session.Tables())
1292    
1293  # Table menu  # Table menu
1294  _method_command("table_open", _("&Open..."), "TableOpen")  _method_command("table_open", _("&Open..."), "TableOpen",
1295  _method_command("table_close", _("&Close"), "TableClose",                  helptext = _("Open a DBF-table from a file"))
1296         sensitive = lambda context: bool(context.session.UnreferencedTables()))  _method_command("table_close", _("&Close..."), "TableClose",
1297  _method_command("table_show", _("&Show"), "TableShow")         sensitive = lambda context: bool(context.session.UnreferencedTables()),
1298  _method_command("table_join", _("&Join..."), "TableJoin")                  helptext = _("Close one or more tables from a list"))
1299    _method_command("table_rename", _("&Rename..."), "TableRename",
1300                    sensitive = _has_tables,
1301                    helptext = _("Rename one or more tables"))
1302    _method_command("table_show", _("&Show..."), "TableShow",
1303                    sensitive = _has_tables,
1304                    helptext = _("Show one or more tables in a dialog"))
1305    _method_command("table_join", _("&Join..."), "TableJoin",
1306                    sensitive = _has_tables,
1307                    helptext = _("Join two tables creating a new one"))
1308    
1309  #  Export only under Windows ...  #  Export only under Windows ...
1310  map_menu = ["layer_add", "rasterlayer_add", "layer_remove", "map_rename",  map_menu = ["layer_add", "layer_add_db", "rasterlayer_add", "layer_remove",
1311                          None,                          None,
1312                            "map_rename",
1313                          "map_projection",                          "map_projection",
1314                          None,                          None,
1315                          "map_zoom_in_tool", "map_zoom_out_tool",                          "map_zoom_in_tool", "map_zoom_out_tool",
1316                          "map_pan_tool",                          "map_pan_tool",
1317                          "map_full_extent",                          "map_full_extent",
1318                          "layer_full_extent",                          "layer_full_extent",
1319                          "selected_full_extent",                          "selected_full_extent",
1320                          None,                          None,
# Line 951  map_menu = ["layer_add", "rasterlayer_ad Line 1322  map_menu = ["layer_add", "rasterlayer_ad
1322                          None,                          None,
1323                          "toggle_legend",                          "toggle_legend",
1324                          None]                          None]
1325  if wxPlatform == '__WXMSW__':  if wx.Platform == '__WXMSW__':
1326      map_menu.append("map_export")      map_menu.append("map_export")
1327  map_menu.append("map_print")  map_menu.append("map_print")
1328    
# Line 960  main_menu = Menu("<main>", "<main>", Line 1331  main_menu = Menu("<main>", "<main>",
1331                   [Menu("file", _("&File"),                   [Menu("file", _("&File"),
1332                         ["new_session", "open_session", None,                         ["new_session", "open_session", None,
1333                          "save_session", "save_session_as", None,                          "save_session", "save_session_as", None,
1334                            "database_management", None,
1335                          "toggle_session_tree", None,                          "toggle_session_tree", None,
1336                          "exit"]),                          "exit"]),
1337                    Menu("map", _("&Map"), map_menu),                    Menu("map", _("&Map"), map_menu),
1338                    Menu("layer", _("&Layer"),                    Menu("layer", _("&Layer"),
1339                          ["layer_raise", "layer_lower",                         ["layer_rename", "layer_duplicate",
1340                            None,
1341                            "layer_raise", "layer_lower",
1342                          None,                          None,
1343                          "layer_show", "layer_hide",                          "layer_show", "layer_hide",
1344                          None,                          None,
# Line 976  main_menu = Menu("<main>", "<main>", Line 1350  main_menu = Menu("<main>", "<main>",
1350                          None,                          None,
1351                          "layer_properties"]),                          "layer_properties"]),
1352                    Menu("table", _("&Table"),                    Menu("table", _("&Table"),
1353                         ["table_open", "table_close",                         ["table_open", "table_close", "table_rename",
1354                         None,                         None,
1355                         "table_show",                         "table_show",
1356                         None,                         None,
# Line 987  main_menu = Menu("<main>", "<main>", Line 1361  main_menu = Menu("<main>", "<main>",
1361  # the main toolbar  # the main toolbar
1362    
1363  main_toolbar = Menu("<toolbar>", "<toolbar>",  main_toolbar = Menu("<toolbar>", "<toolbar>",
1364                      ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",                      ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
1365                       "map_full_extent",                       "map_full_extent",
1366                       "layer_full_extent",                       "layer_full_extent",
1367                       "selected_full_extent",                       "selected_full_extent",
1368                       None,                       None,
1369                       "map_identify_tool", "map_label_tool"])                       "map_identify_tool", "map_label_tool"])
1370    

Legend:
Removed from v.1070  
changed lines
  Added in v.2734

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26