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

Legend:
Removed from v.487  
changed lines
  Added in v.1287

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26