/[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 37 by bh, Thu Sep 6 17:16:54 2001 UTC revision 923 by frank, Mon May 19 09:12:25 2003 UTC
# Line 1  Line 1 
1  # Copyright (C) 2001 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  import sys, os  __ThubanVersion__ = "0.2" #"$THUBAN_0_2$"
17    #__BuildDate__ = "$Date$"
18    
19    import os
20    
21  from wxPython.wx import *  from wxPython.wx import *
22    from wxPython.wx import __version__ as wxPython_version
23    
24  import Thuban  import Thuban
25  from Thuban.Model.session import Session  import Thuban.version
26  from Thuban.Model.map import Map  
27    from Thuban import _
28    from Thuban.Model.session import create_empty_session
29  from Thuban.Model.layer import Layer  from Thuban.Model.layer import Layer
30  from Thuban.Model.color import Color  from Thuban.Model.color import Color
31  from Thuban.Model.proj import Projection  from Thuban.Model.proj import Projection
# Line 27  import view Line 34  import view
34  import tree  import tree
35  import proj4dialog  import proj4dialog
36  import tableview, identifyview  import tableview, identifyview
37    from Thuban.UI.classifier import Classifier
38    import legend
39    from menu import Menu
40    
41    from context import Context
42    from command import registry, Command, ToolCommand
43    from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION
44    
45    from Thuban.UI.dock import DockFrame
46    from Thuban.UI.join import JoinDialog
47    
48    import resource
49    
50  import main  import projdialog
 from command import registry, Command  
 from messages import SELECTED_SHAPE  
51    
52    
 # the directory where the toolbar icons are stored  
 bitmapdir = os.path.join(Thuban.__path__[0], os.pardir, "Resources", "Bitmaps")  
 bitmapext = ".xpm"  
53    
54    class MainWindow(DockFrame):
55    
56  class MainWindow(wxFrame):      # Some messages that can be subscribed/unsubscribed directly through
57        # the MapCanvas come in fact from other objects. This is a map to
58        # map those messages to the names of the instance variables they
59        # actually come from. This delegation is implemented in the
60        # Subscribe and unsubscribed methods
61        delegated_messages = {LAYER_SELECTED: "canvas",
62                              SHAPES_SELECTED: "canvas"}
63    
64      def __init__(self, parent, ID, interactor):      # Methods delegated to some instance variables. The delegation is
65          wxFrame.__init__(self, parent, ID, 'Thuban',      # implemented in the __getattr__ method.
66                           wxDefaultPosition, wxSize(400, 300))      delegated_methods = {"SelectLayer": "canvas",
67                             "SelectShapes": "canvas",
68                             "SelectedShapes": "canvas",
69                             }
70    
71          self.interactor = interactor      def __init__(self, parent, ID, title, application, interactor,
72                     initial_message = None, size = wxSize(-1, -1)):
73            DockFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
74            #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
75    
76            self.application = application
77    
78          self.CreateStatusBar()          self.CreateStatusBar()
79          self.SetStatusText("This is the wxPython-based "          if initial_message:
80                        "Graphical User Interface for exploring geographic data")              self.SetStatusText(initial_message)
81    
82          self.identify_view = None          self.identify_view = None
83    
84          self.init_ids()          self.init_ids()
85    
86          menuBar = wxMenuBar()          # creat the menubar from the main_menu description
87            self.SetMenuBar(self.build_menu_bar(main_menu))
         menu = wxMenu()  
         menuBar.Append(menu, "&File");  
         for name in ["new_session", "open_session", None,  
                      "save_session", "save_session_as", None,  
                      "exit"]:  
             self.add_menu_command(menu, name)  
   
         menu = wxMenu()  
         menuBar.Append(menu, "&Map");  
         for name in ["map_projection",  
                      None,  
                      "map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",  
                      "map_identify_tool", "map_label_tool",  
                      None,  
                      "map_full_extent",  
                      None,  
                      "map_print"]:  
             self.add_menu_command(menu, name)  
   
         menu = wxMenu()  
         menuBar.Append(menu, "&Layer");  
         for name in ["layer_add", "layer_remove",  
                      None,  
                      "layer_fill_color", "layer_transparent_fill",  
                      "layer_ourline_color", "layer_no_outline",  
                      None,  
                      "layer_raise", "layer_lower",  
                      None,  
                      "layer_show", "layer_hide",  
                      None,  
                      "layer_show_table"]:  
             self.add_menu_command(menu, name)  
   
         menu = wxMenu()  
         menuBar.Append(menu, "&Help");  
         self.add_menu_command(menu, "help_about")  
   
         self.SetMenuBar(menuBar)  
88    
89          # toolbar          # Similarly, create the toolbar from main_toolbar
90          toolbar = self.CreateToolBar(wxTB_3DBUTTONS)          toolbar = self.build_toolbar(main_toolbar)
         for name in ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",  
                      "map_identify_tool", "map_label_tool"]:  
             self.add_toolbar_command(toolbar, name)  
91          # call Realize to make sure that the tools appear.          # call Realize to make sure that the tools appear.
92          toolbar.Realize()          toolbar.Realize()
93    
94    
95          # Create the map canvas          # Create the map canvas
96          canvas = view.MapCanvas(self, -1, interactor)          canvas = view.MapCanvas(self, -1)
97            canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
98            canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
99          self.canvas = canvas          self.canvas = canvas
100    
101            self.SetMainWindow(self.canvas)
102    
103            self.SetAutoLayout(True)
104    
105          self.init_dialogs()          self.init_dialogs()
106    
107          interactor.Subscribe(SELECTED_SHAPE, self.identify_view_on_demand)          EVT_CLOSE(self, self._OnClose)
108    
109        def Subscribe(self, channel, *args):
110            """Subscribe a function to a message channel.
111    
112            If channel is one of the delegated messages call the appropriate
113            object's Subscribe method. Otherwise do nothing.
114            """
115            if channel in self.delegated_messages:
116                object = getattr(self, self.delegated_messages[channel])
117                object.Subscribe(channel, *args)
118            else:
119                print "Trying to subscribe to unsupported channel %s" % channel
120    
121        def Unsubscribe(self, channel, *args):
122            """Unsubscribe a function from a message channel.
123    
124          EVT_CLOSE(self, self.OnClose)          If channel is one of the delegated messages call the appropriate
125            object's Unsubscribe method. Otherwise do nothing.
126            """
127            if channel in self.delegated_messages:
128                object = getattr(self, self.delegated_messages[channel])
129                object.Unsubscribe(channel, *args)
130    
131        def __getattr__(self, attr):
132            """If attr is one of the delegated methods return that method
133    
134            Otherwise raise AttributeError.
135            """
136            if attr in self.delegated_methods:
137                return getattr(getattr(self, self.delegated_methods[attr]), attr)
138            raise AttributeError(attr)
139    
140      def init_ids(self):      def init_ids(self):
141          """Initialize the ids"""          """Initialize the ids"""
142          self.current_id = 6000          self.current_id = 6000
143          self.id_to_name = {}          self.id_to_name = {}
144          self.name_to_id = {}          self.name_to_id = {}
145            self.events_bound = {}
146    
147      def get_id(self, name):      def get_id(self, name):
148          """Return the wxWindows id for the command named name.          """Return the wxWindows id for the command named name.
# Line 130  class MainWindow(wxFrame): Line 155  class MainWindow(wxFrame):
155              self.name_to_id[name] = ID              self.name_to_id[name] = ID
156              self.id_to_name[ID] = name              self.id_to_name[ID] = name
157          return ID          return ID
158            
159        def bind_command_events(self, command, ID):
160            """Bind the necessary events for the given command and ID"""
161            if not self.events_bound.has_key(ID):
162                # the events haven't been bound yet
163                EVT_MENU(self, ID, self.invoke_command)
164                if command.IsDynamic():
165                    EVT_UPDATE_UI(self, ID, self.update_command_ui)
166    
167        def build_menu_bar(self, menudesc):
168            """Build and return the menu bar from the menu description"""
169            menu_bar = wxMenuBar()
170    
171            for item in menudesc.items:
172                # here the items must all be Menu instances themselves
173                menu_bar.Append(self.build_menu(item), item.title)
174    
175            return menu_bar
176    
177        def build_menu(self, menudesc):
178            """Return a wxMenu built from the menu description menudesc"""
179            wxmenu = wxMenu()
180            last = None
181            for item in menudesc.items:
182                if item is None:
183                    # a separator. Only add one if the last item was not a
184                    # separator
185                    if last is not None:
186                        wxmenu.AppendSeparator()
187                elif isinstance(item, Menu):
188                    # a submenu
189                    wxmenu.AppendMenu(wxNewId(), item.title, self.build_menu(item))
190                else:
191                    # must the name the name of a command
192                    self.add_menu_command(wxmenu, item)
193                last = item
194            return wxmenu
195    
196        def build_toolbar(self, toolbardesc):
197            """Build and return the main toolbar window from a toolbar description
198    
199            The parameter should be an instance of the Menu class but it
200            should not contain submenus.
201            """
202            toolbar = self.CreateToolBar(wxTB_3DBUTTONS)
203    
204            # set the size of the tools' bitmaps. Not needed on wxGTK, but
205            # on Windows, although it doesn't work very well there. It seems
206            # that only 16x16 icons are really supported on windows.
207            # We probably shouldn't hardwire the bitmap size here.
208            toolbar.SetToolBitmapSize(wxSize(24, 24))
209    
210            for item in toolbardesc.items:
211                if item is None:
212                    toolbar.AddSeparator()
213                else:
214                    # assume it's a string.
215                    self.add_toolbar_command(toolbar, item)
216    
217            return toolbar
218    
219      def add_menu_command(self, menu, name):      def add_menu_command(self, menu, name):
220          """Add the command with name name to the menu menu.          """Add the command with name name to the menu menu.
221    
# Line 144  class MainWindow(wxFrame): Line 229  class MainWindow(wxFrame):
229                  ID = self.get_id(name)                  ID = self.get_id(name)
230                  menu.Append(ID, command.Title(), command.HelpText(),                  menu.Append(ID, command.Title(), command.HelpText(),
231                              command.IsCheckCommand())                              command.IsCheckCommand())
232                  EVT_MENU(self, ID, self.invoke_command)                  self.bind_command_events(command, ID)
                 if command.IsDynamic():  
                     EVT_UPDATE_UI(self, ID, self.update_command_ui)  
233              else:              else:
234                  print "Unknown command %s" % name                  print _("Unknown command %s") % name
235    
236      def add_toolbar_command(self, toolbar, name):      def add_toolbar_command(self, toolbar, name):
237          """Add the command with name name to the toolbar toolbar.          """Add the command with name name to the toolbar toolbar.
# Line 163  class MainWindow(wxFrame): Line 246  class MainWindow(wxFrame):
246              command = registry.Command(name)              command = registry.Command(name)
247              if command is not None:              if command is not None:
248                  ID = self.get_id(name)                  ID = self.get_id(name)
249                  filename = os.path.join(bitmapdir, command.Icon()) + bitmapext                  bitmap = resource.GetBitmapResource(command.Icon(),
250                  bitmap = wxBitmap(filename, wxBITMAP_TYPE_XPM)                                                      wxBITMAP_TYPE_XPM)
251                  toolbar.AddTool(ID, bitmap,                  toolbar.AddTool(ID, bitmap,
252                                  shortHelpString = command.HelpText(),                                  shortHelpString = command.HelpText(),
253                                  isToggle = command.IsCheckCommand())                                  isToggle = command.IsCheckCommand())
254                    self.bind_command_events(command, ID)
255              else:              else:
256                  print "Unknown command %s" % name                  print _("Unknown command %s") % name
257    
258        def Context(self):
259            """Return the context object for a command invoked from this window
260            """
261            return Context(self.application, self.application.Session(), self)
262    
263      def invoke_command(self, event):      def invoke_command(self, event):
264          name = self.id_to_name.get(event.GetId())          name = self.id_to_name.get(event.GetId())
265          if name is not None:          if name is not None:
266              command = registry.Command(name)              command = registry.Command(name)
267              command.Execute(self)              command.Execute(self.Context())
268          else:          else:
269              print "Unknown command ID %d" % event.GetId()              print _("Unknown command ID %d") % event.GetId()
270    
271      def update_command_ui(self, event):      def update_command_ui(self, event):
272          #print "update_command_ui", self.id_to_name[event.GetId()]          #print "update_command_ui", self.id_to_name[event.GetId()]
273            context = self.Context()
274          command = registry.Command(self.id_to_name[event.GetId()])          command = registry.Command(self.id_to_name[event.GetId()])
275          if command is not None:          if command is not None:
276              event.Enable(command.Sensitive(self))              sensitive = command.Sensitive(context)
277              event.SetText(command.DynText(self))              event.Enable(sensitive)
278                if command.IsTool() and not sensitive and command.Checked(context):
279                    # When a checked tool command is disabled deselect all
280                    # tools. Otherwise the tool would remain active but it
281                    # might lead to errors if the tools stays active. This
282                    # problem occurred in GREAT-ER and this fixes it, but
283                    # it's not clear to me whether this is really the best
284                    # way to do it (BH, 20021206).
285                    self.canvas.SelectTool(None)
286                event.SetText(command.DynText(context))
287              if command.IsCheckCommand():              if command.IsCheckCommand():
288                  event.Check(command.Checked(self))                      event.Check(command.Checked(context))
289    
290      def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):      def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
291          """Run a modla message box with the given text, title and flags          """Run a modal message box with the given text, title and flags
292          and return the result"""          and return the result"""
293          dlg = wxMessageDialog(self, text, title, flags)          dlg = wxMessageDialog(self, text, title, flags)
294            dlg.CenterOnParent()
295          result = dlg.ShowModal()          result = dlg.ShowModal()
296          dlg.Destroy()          dlg.Destroy()
297          return result          return result
# Line 205  class MainWindow(wxFrame): Line 305  class MainWindow(wxFrame):
305    
306      def add_dialog(self, name, dialog):      def add_dialog(self, name, dialog):
307          if self.dialogs.has_key(name):          if self.dialogs.has_key(name):
308              raise RuntimeError("The Dialog named %s is already open" % name)              raise RuntimeError(_("The Dialog named %s is already open") % name)
309          self.dialogs[name] = dialog          self.dialogs[name] = dialog
310    
311      def dialog_open(self, name):      def dialog_open(self, name):
# Line 217  class MainWindow(wxFrame): Line 317  class MainWindow(wxFrame):
317      def get_open_dialog(self, name):      def get_open_dialog(self, name):
318          return self.dialogs.get(name)          return self.dialogs.get(name)
319    
320        def view_position_changed(self):
321            pos = self.canvas.CurrentPosition()
322            if pos is not None:
323                text = "(%10.10g, %10.10g)" % pos
324            else:
325                text = ""
326            self.set_position_text(text)
327    
328        def set_position_text(self, text):
329            """Set the statusbar text showing the current position.
330    
331            By default the text is shown in field 0 of the status bar.
332            Override this method in derived classes to put it into a
333            different field of the statusbar.
334            """
335            self.SetStatusText(text)
336    
337        def save_modified_session(self, can_veto = 1):
338            """If the current session has been modified, ask the user
339            whether to save it and do so if requested. Return the outcome of
340            the dialog (either wxID_OK, wxID_CANCEL or wxID_NO). If the
341            dialog wasn't run return wxID_NO.
342    
343            If the can_veto parameter is true (default) the dialog includes
344            a cancel button, otherwise not.
345            """
346            if self.application.session.WasModified():
347                flags = wxYES_NO | wxICON_QUESTION
348                if can_veto:
349                    flags = flags | wxCANCEL
350                result = self.RunMessageBox(_("Exit"),
351                                            _("The session has been modified."
352                                             " Do you want to save it?"),
353                                            flags)
354                if result == wxID_YES:
355                    self.SaveSession()
356            else:
357                result = wxID_NO
358            return result
359    
360        def prepare_new_session(self):
361            for d in self.dialogs.values():
362                if not isinstance(d, tree.SessionTreeView):
363                    d.Close()
364    
365      def NewSession(self):      def NewSession(self):
366          session = Session("")          self.save_modified_session()
367          session.AddMap(Map(""))          self.prepare_new_session()
368          main.app.SetSession(session)          self.application.SetSession(create_empty_session())
369    
370      def OpenSession(self):      def OpenSession(self):
371          dlg = wxFileDialog(self, "Select a session file", ".", "",          self.save_modified_session()
372                             "*.session", wxOPEN)          dlg = wxFileDialog(self, _("Open Session"), ".", "",
373                               "Thuban Session File (*.thuban)|*.thuban", wxOPEN)
374          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
375              main.app.OpenSession(dlg.GetPath())              self.prepare_new_session()
376                self.application.OpenSession(dlg.GetPath())
377          dlg.Destroy()          dlg.Destroy()
378    
379      def SaveSession(self):      def SaveSession(self):
380          main.app.SaveSession()          if self.application.session.filename == None:
381                self.SaveSessionAs()
382            else:
383                self.application.SaveSession()
384    
385      def SaveSessionAs(self):      def SaveSessionAs(self):
386          dlg = wxFileDialog(self, "Enter a filename for session", ".", "",          dlg = wxFileDialog(self, _("Save Session As"), ".", "",
387                             "*.session", wxOPEN)                             "Thuban Session File (*.thuban)|*.thuban",
388                               wxSAVE|wxOVERWRITE_PROMPT)
389          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
390              main.app.session.SetFilename(dlg.GetPath())              self.application.session.SetFilename(dlg.GetPath())
391              main.app.SaveSession()              self.application.SaveSession()
392          dlg.Destroy()          dlg.Destroy()
393    
394      def Exit(self):      def Exit(self):
395          self.Close(false)          self.Close(False)
   
     def OnClose(self, event):  
         veto = 0  
         if main.app.session.WasModified():  
             flags = wxYES_NO | wxICON_QUESTION  
             if event.CanVeto():  
                 flags = flags | wxCANCEL  
             result = self.RunMessageBox("Exit",  
                                         ("The session has been modified."  
                                          " Do you want to save it?"),  
                                         flags)  
             if result == wxID_YES:  
                 self.SaveSession()  
             elif result == wxID_CANCEL:  
                 veto = 1  
396    
397          if veto:      def _OnClose(self, event):
398            result = self.save_modified_session(can_veto = event.CanVeto())
399            if result == wxID_CANCEL:
400              event.Veto()              event.Veto()
401          else:          else:
402                # FIXME: it would be better to tie the unsubscription to
403                # wx's destroy event, but that isn't implemented for wxGTK
404                # yet.
405                self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
406                DockFrame._OnClose(self, event)
407              self.Destroy()              self.Destroy()
408    
409      def SetMap(self, map):      def SetMap(self, map):
410          self.canvas.SetMap(map)          self.canvas.SetMap(map)
411            self.__SetTitle(map.Title())
412    
413      def ShowSessionTree(self):          dialog = self.FindRegisteredDock("legend")
414            if dialog is not None:
415                dialog.GetPanel().SetMap(self.Map())
416    
417        def Map(self):
418            """Return the map displayed by this mainwindow"""
419    
420            return self.canvas.Map()
421    
422        def ToggleSessionTree(self):
423            """If the session tree is shown close it otherwise create a new tree"""
424          name = "session_tree"          name = "session_tree"
425          dialog = self.get_open_dialog(name)          dialog = self.get_open_dialog(name)
426          if dialog is None:          if dialog is None:
427              dialog = tree.SessionTreeView(self, main.app, name)              dialog = tree.SessionTreeView(self, self.application, name)
428              self.add_dialog(name, dialog)              self.add_dialog(name, dialog)
429              dialog.Show(true)              dialog.Show(True)
430          else:          else:
431              # FIXME: bring dialog to front here              dialog.Close()
432              pass  
433        def SessionTreeShown(self):
434            """Return true iff the session tree is currently shown"""
435            return self.get_open_dialog("session_tree") is not None
436    
437      def About(self):      def About(self):
438          self.RunMessageBox("About",          self.RunMessageBox(_("About"),
439                             ("Thuban is a program for\n"                             _("Thuban %s\n"
440                                #"Build Date: %s\n"
441                                "using:\n"
442                                "  %s\n"
443                                "  %s\n\n"
444                                "Thuban is a program for\n"
445                              "exploring geographic data.\n"                              "exploring geographic data.\n"
446                              "Copyright (C) 2001 Intevation GmbH.\n"                              "Copyright (C) 2001-2003 Intevation GmbH.\n"
447                              "Thuban is licensed under the GPL"),                              "Thuban is licensed under the GNU GPL"
448                                % (Thuban.version.longversion,
449                                   "wxPython %s" % wxPython_version,
450                                   "Python %d.%d.%d" % sys.version_info[:3]
451                                  )),
452    #                           % __ThubanVersion__), #__BuildDate__)),
453                             wxOK | wxICON_INFORMATION)                             wxOK | wxICON_INFORMATION)
454    
455      def AddLayer(self):      def AddLayer(self):
456          dlg = wxFileDialog(self, "Select a session file", ".", "", "*.*",          dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
457                             wxOPEN)                             wxOPEN)
458          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
459              filename = dlg.GetPath()              filename = dlg.GetPath()
460              title = os.path.splitext(os.path.basename(filename))[0]              title = os.path.splitext(os.path.basename(filename))[0]
461              layer = Layer(title, filename)              store = self.application.Session().OpenShapefile(filename)
462                layer = Layer(title, store)
463              map = self.canvas.Map()              map = self.canvas.Map()
464              has_layers = map.HasLayers()              has_layers = map.HasLayers()
465              try:              try:
466                  map.AddLayer(layer)                  map.AddLayer(layer)
467              except IOError:              except IOError:
468                  # the layer couldn't be opened                  # the layer couldn't be opened
469                  self.RunMessageBox("Add Layer",                  self.RunMessageBox(_("Add Layer"),
470                                     "Can't open the file '%s'." % filename)                                     _("Can't open the file '%s'.") % filename)
471              else:              else:
472                  if not has_layers:                  if not has_layers:
473                      # if we're adding a layer to an empty map, for the                      # if we're adding a layer to an empty map, fit the
474                      # new map to the window                      # new map to the window
475                      self.canvas.FitMapToWindow()                      self.canvas.FitMapToWindow()
476          dlg.Destroy()          dlg.Destroy()
# Line 312  class MainWindow(wxFrame): Line 480  class MainWindow(wxFrame):
480          if layer is not None:          if layer is not None:
481              self.canvas.Map().RemoveLayer(layer)              self.canvas.Map().RemoveLayer(layer)
482    
483        def CanRemoveLayer(self):
484            """Return true if the currently selected layer can be deleted.
485    
486            If no layer is selected return False.
487    
488            The return value of this method determines whether the remove
489            layer command is sensitive in menu.
490            """
491            layer = self.current_layer()
492            if layer is not None:
493                return self.canvas.Map().CanRemoveLayer(layer)
494            return False
495    
496      def RaiseLayer(self):      def RaiseLayer(self):
497          layer = self.current_layer()          layer = self.current_layer()
498          if layer is not None:          if layer is not None:
499              self.canvas.Map().RaiseLayer(layer)              self.canvas.Map().RaiseLayer(layer)
500            
501      def LowerLayer(self):      def LowerLayer(self):
502          layer = self.current_layer()          layer = self.current_layer()
503          if layer is not None:          if layer is not None:
# Line 327  class MainWindow(wxFrame): Line 508  class MainWindow(wxFrame):
508    
509          If no layer is selected, return None          If no layer is selected, return None
510          """          """
511          return self.interactor.SelectedLayer()          return self.canvas.SelectedLayer()
512    
513      def has_selected_layer(self):      def has_selected_layer(self):
514          """Return true if a layer is currently selected"""          """Return true if a layer is currently selected"""
515          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  
   
     def LayerFillColor(self):  
         layer = self.current_layer()  
         if layer is not None:  
             color = self.choose_color()  
             if color is not None:  
                 layer.SetFill(color)  
   
     def LayerTransparentFill(self):  
         layer = self.current_layer()  
         if layer is not None:  
             layer.SetFill(None)  
516    
517      def LayerOutlineColor(self):      def has_selected_shapes(self):
518          layer = self.current_layer()          """Return true if a shape is currently selected"""
519          if layer is not None:          return self.canvas.HasSelectedShapes()
             color = self.choose_color()  
             if color is not None:  
                 layer.SetStroke(color)  
   
     def LayerNoOutline(self):  
         layer = self.current_layer()  
         if layer is not None:  
             layer.SetStroke(None)  
520    
521      def HideLayer(self):      def HideLayer(self):
522          layer = self.current_layer()          layer = self.current_layer()
# Line 390  class MainWindow(wxFrame): Line 535  class MainWindow(wxFrame):
535              name = "table_view" + str(id(table))              name = "table_view" + str(id(table))
536              dialog = self.get_open_dialog(name)              dialog = self.get_open_dialog(name)
537              if dialog is None:              if dialog is None:
538                  dialog = tableview.TableFrame(self, self.interactor, name,                  dialog = tableview.LayerTableFrame(self, name,
539                                                "Table: %s" % layer.Title(),                                                 _("Table: %s") % layer.Title(),
540                                                layer, table)                                                     layer, table)
541                  self.add_dialog(name, dialog)                  self.add_dialog(name, dialog)
542                  dialog.Show(true)                  dialog.Show(true)
543              else:              else:
544                  # FIXME: bring dialog to front here                  # FIXME: bring dialog to front here
545                  pass                  pass
546    
547      def Projection(self):      def MapProjection(self):
548          map = self.canvas.Map()  
549          proj = map.projection          name = "map_projection"
550          if proj is None:          dialog = self.get_open_dialog(name)
551              proj4Dlg = proj4dialog.Proj4Dialog(NULL, None)  
552            if dialog is None:
553                map = self.canvas.Map()
554                dialog = projdialog.ProjFrame(self, name,
555                         _("Map Projection: %s") % map.Title(), map)
556                self.add_dialog(name, dialog)
557                dialog.Show()
558            dialog.Raise()
559    
560        def LayerProjection(self):
561    
562            layer = self.current_layer()
563    
564            name = "layer_projection" + str(id(layer))
565            dialog = self.get_open_dialog(name)
566    
567            if dialog is None:
568                map = self.canvas.Map()
569                dialog = projdialog.ProjFrame(self, name,
570                         _("Layer Projection: %s") % layer.Title(), layer)
571                self.add_dialog(name, dialog)
572                dialog.Show()
573            dialog.Raise()
574    
575        def LayerEditProperties(self):
576    
577            #
578            # the menu option for this should only be available if there
579            # is a current layer, so we don't need to check if the
580            # current layer is None
581            #
582    
583            layer = self.current_layer()
584            self.OpenLayerProperties(layer)
585    
586        def OpenLayerProperties(self, layer, group = None):
587            name = "layer_properties" + str(id(layer))
588            dialog = self.get_open_dialog(name)
589    
590            if dialog is None:
591                dialog = Classifier(self, name, layer, group)
592                self.add_dialog(name, dialog)
593                dialog.Show()
594            dialog.Raise()
595    
596        def LayerJoinTable(self):
597            print "LayerJoinTable"
598    
599        def LayerUnjoinTable(self):
600            print "LayerUnjoinTable"
601    
602        def ShowLegend(self):
603            if not self.LegendShown():
604                self.ToggleLegend()
605    
606        def ToggleLegend(self):
607            """Show the legend if it's not shown otherwise hide it again"""
608            name = "legend"
609            dialog = self.FindRegisteredDock(name)
610    
611            if dialog is None:
612                dialog = self.CreateDock(name, -1, _("Legend"), wxLAYOUT_LEFT)
613                legend.LegendPanel(dialog, None, self)
614                dialog.Dock()
615                dialog.GetPanel().SetMap(self.Map())
616                dialog.Show()
617          else:          else:
618              proj4Dlg = proj4dialog.Proj4Dialog(NULL, map.projection.params)              dialog.Show(not dialog.IsShown())
619          if proj4Dlg.ShowModal() == wxID_OK:  
620              params = proj4Dlg.GetParams()      def LegendShown(self):
621              if params is not None:          """Return true iff the legend is currently open"""
622                  proj = Projection(params)          dialog = self.FindRegisteredDock("legend")
623              else:          return dialog is not None and dialog.IsShown()
624                  proj = None  
625              map.SetProjection(proj)      def TableOpen(self):
626          proj4Dlg.Destroy()          print "TableOpen"
627            dlg = wxFileDialog(self, _("Open Table"), ".", "",
628                               "DBF Files (*.dbf)|*.dbf|" +
629                               "CSV Files (*.csv)|*.csv|" +
630                               "All Files (*.*)|*.*",
631                               wxOPEN)
632            if dlg.ShowModal() == wxID_OK:
633                #self.application.session.OpenTable(dlg.GetPath())
634                pass
635    
636            dlg.Destroy()
637    
638        def TableClose(self):
639            print "TableClose"
640    
641        def TableShow(self):
642            print "TableShow"
643    
644        def TableHide(self):
645            print "TableHide"
646    
647        def TableJoin(self):
648            print "TableJoin"
649            dlg = JoinDialog(self, _("Join Tables"), self.application.session)
650            if dlg.ShowModal() == wxID_OK:
651                print "OK"
652    
653      def ZoomInTool(self):      def ZoomInTool(self):
654          self.canvas.ZoomInTool()          self.canvas.ZoomInTool()
# Line 426  class MainWindow(wxFrame): Line 661  class MainWindow(wxFrame):
661    
662      def IdentifyTool(self):      def IdentifyTool(self):
663          self.canvas.IdentifyTool()          self.canvas.IdentifyTool()
664            self.identify_view_on_demand(None, None)
665    
666      def LabelTool(self):      def LabelTool(self):
667          self.canvas.LabelTool()          self.canvas.LabelTool()
# Line 433  class MainWindow(wxFrame): Line 669  class MainWindow(wxFrame):
669      def FullExtent(self):      def FullExtent(self):
670          self.canvas.FitMapToWindow()          self.canvas.FitMapToWindow()
671    
672        def FullLayerExtent(self):
673            self.canvas.FitLayerToWindow(self.current_layer())
674    
675        def FullSelectionExtent(self):
676            self.canvas.FitSelectedToWindow()
677    
678        def ExportMap(self):
679            self.canvas.Export()
680    
681      def PrintMap(self):      def PrintMap(self):
682          self.canvas.Print()          self.canvas.Print()
683    
684      def identify_view_on_demand(self, layer, shape):      def RenameMap(self):
685            dlg = wxTextEntryDialog(self, "Map Title: ", "Rename Map",
686                                    self.Map().Title())
687            if dlg.ShowModal() == wxID_OK:
688                title = dlg.GetValue()
689                if title != "":
690                    self.Map().SetTitle(title)
691                    self.__SetTitle(title)
692    
693            dlg.Destroy()
694    
695        def identify_view_on_demand(self, layer, shapes):
696            """Subscribed to the canvas' SHAPES_SELECTED message
697    
698            If the current tool is the identify tool, at least one shape is
699            selected and the identify dialog is not shown, show the dialog.
700            """
701            # If the selection has become empty we don't need to do
702            # anything. Otherwise it could happen that the dialog was popped
703            # up when the selection became empty, e.g. when a new selection
704            # is opened while the identify tool is active and dialog had
705            # been closed
706            if not shapes:
707                return
708    
709          name = "identify_view"          name = "identify_view"
710          if self.canvas.CurrentTool() == "IdentifyTool":          if self.canvas.CurrentTool() == "IdentifyTool":
711              if not self.dialog_open(name):              if not self.dialog_open(name):
712                  dialog = identifyview.IdentifyView(self, self.interactor, name)                  dialog = identifyview.IdentifyView(self, name)
713                  self.add_dialog(name, dialog)                  self.add_dialog(name, dialog)
714                  dialog.Show(true)                  dialog.Show(True)
715              else:              else:
716                  # FIXME: bring dialog to front?                  # FIXME: bring dialog to front?
717                  pass                  pass
718    
719        def __SetTitle(self, title):
720            self.SetTitle("Thuban - " + title)
721    
722  #  #
723  # Define all the commands available in the main window  # Define all the commands available in the main window
724  #  #
# Line 454  class MainWindow(wxFrame): Line 726  class MainWindow(wxFrame):
726    
727  # Helper functions to define common command implementations  # Helper functions to define common command implementations
728  def call_method(context, methodname, *args):  def call_method(context, methodname, *args):
729      """Call the context's method methodname with args *args"""      """Call the mainwindow's method methodname with args *args"""
730      apply(getattr(context, methodname), args)      apply(getattr(context.mainwindow, methodname), args)
731    
732  def _method_command(name, title, method, helptext = "", sensitive = None):  def _method_command(name, title, method, helptext = "",
733      """Add a command implemented by a method of the context object"""                      icon = "", sensitive = None, checked = None):
734        """Add a command implemented by a method of the mainwindow object"""
735      registry.Add(Command(name, title, call_method, args=(method,),      registry.Add(Command(name, title, call_method, args=(method,),
736                           helptext = helptext, sensitive = sensitive))                           helptext = helptext, icon = icon,
737                             sensitive = sensitive, checked = checked))
738    
739    def make_check_current_tool(toolname):
740        """Return a function that tests if the currently active tool is toolname
741    
742        The returned function can be called with the context and returns
743        true iff the currently active tool's name is toolname. It's directly
744        usable as the 'checked' callback of a command.
745        """
746        def check_current_tool(context, name=toolname):
747            return context.mainwindow.canvas.CurrentTool() == name
748        return check_current_tool
749    
750  def _tool_command(name, title, method, toolname, helptext = "",  def _tool_command(name, title, method, toolname, helptext = "",
751                    icon = ""):                    icon = "", sensitive = None):
752      """Add a tool command"""      """Add a tool command"""
753      def check_current_tool(context, name=toolname):      registry.Add(ToolCommand(name, title, call_method, args=(method,),
754          return context.canvas.CurrentTool() == name                               helptext = helptext, icon = icon,
755      registry.Add(Command(name, title, call_method, args=(method,),                               checked = make_check_current_tool(toolname),
756                           helptext = helptext, icon = icon,                               sensitive = sensitive))
                          checked = check_current_tool))  
757    
758  def _has_selected_layer(context):  def _has_selected_layer(context):
759      """Return true if a layer is selected in the context"""      """Return true if a layer is selected in the context"""
760      return context.has_selected_layer()      return context.mainwindow.has_selected_layer()
761    
762    def _has_selected_shapes(context):
763        """Return true if a layer is selected in the context"""
764        return context.mainwindow.has_selected_shapes()
765    
766    def _can_remove_layer(context):
767        return context.mainwindow.CanRemoveLayer()
768    
769    def _has_tree_window_shown(context):
770        """Return true if the tree window is shown"""
771        return context.mainwindow.SessionTreeShown()
772    
773    def _has_visible_map(context):
774        """Return true iff theres a visible map in the mainwindow.
775    
776        A visible map is a map with at least one visible layer."""
777        map = context.mainwindow.Map()
778        if map is not None:
779            for layer in map.Layers():
780                if layer.Visible():
781                    return 1
782        return 0
783    
784    def _has_legend_shown(context):
785        """Return true if the legend window is shown"""
786        return context.mainwindow.LegendShown()
787    
788    
789  # File menu  # File menu
790  _method_command("new_session", "&New Session", "NewSession")  _method_command("new_session", _("&New Session"), "NewSession")
791  _method_command("open_session", "&Open Session", "OpenSession")  _method_command("open_session", _("&Open Session..."), "OpenSession")
792  _method_command("save_session", "&Save Session", "SaveSession")  _method_command("save_session", _("&Save Session"), "SaveSession")
793  _method_command("save_session_as", "Save Session &As", "SaveSessionAs")  _method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs")
794  _method_command("exit", "&Exit", "Exit")  _method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
795                    checked = _has_tree_window_shown)
796    _method_command("toggle_legend", _("Legend"), "ToggleLegend",
797                    checked = _has_legend_shown)
798    _method_command("exit", _("E&xit"), "Exit")
799    
800  # Help menu  # Help menu
801  _method_command("help_about", "&About", "About")  _method_command("help_about", _("&About..."), "About")
802    
803    
804  # Map menu  # Map menu
805  _method_command("map_projection", "Pro&jection", "Projection")  _method_command("map_projection", _("Pro&jection..."), "MapProjection")
806    
807  _tool_command("map_zoom_in_tool", "&Zoom in", "ZoomInTool", "ZoomInTool",  _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
808                helptext = "Switch to map-mode 'zoom-in'", icon = "zoom_in")                helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
809  _tool_command("map_zoom_out_tool", "Zoom &out", "ZoomOutTool", "ZoomOutTool",                sensitive = _has_visible_map)
810                helptext = "Switch to map-mode 'zoom-out'", icon = "zoom_out")  _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
811  _tool_command("map_pan_tool", "&Pan", "PanTool", "PanTool",                helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
812                helptext = "Switch to map-mode 'pan'", icon = "pan")                sensitive = _has_visible_map)
813  _tool_command("map_identify_tool", "&Identify", "IdentifyTool", "IdentifyTool",  _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
814                helptext = "Switch to map-mode 'identify'", icon = "identify")                helptext = _("Switch to map-mode 'pan'"), icon = "pan",
815  _tool_command("map_label_tool", "&Label", "LabelTool", "LabelTool",                sensitive = _has_visible_map)
816                helptext = "Add/Remove labels", icon = "label")  _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
817  _method_command("map_full_extent", "&Full extent", "FullExtent")                "IdentifyTool",
818  _method_command("map_print", "Prin&t", "PrintMap", helptext = "Print the map")                helptext = _("Switch to map-mode 'identify'"), icon = "identify",
819                  sensitive = _has_visible_map)
820    _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
821                  helptext = _("Add/Remove labels"), icon = "label",
822                  sensitive = _has_visible_map)
823    _method_command("map_full_extent", _("&Full extent"), "FullExtent",
824                   helptext = _("Full Extent"), icon = "fullextent",
825                  sensitive = _has_visible_map)
826    _method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
827                   helptext = _("Full Layer Extent"), icon = "fulllayerextent",
828                  sensitive = _has_selected_layer)
829    _method_command("selected_full_extent", _("&Full selection extent"), "FullSelectionExtent",
830                   helptext = _("Full Selection Extent"), icon = "fullselextent",
831                  sensitive = _has_selected_shapes)
832    _method_command("map_export", _("E&xport"), "ExportMap",
833                        helptext = _("Export the map to file"))
834    _method_command("map_print", _("Prin&t"), "PrintMap",
835                    helptext = _("Print the map"))
836    _method_command("map_rename", _("&Rename..."), "RenameMap",
837                    helptext = _("Rename the map"))
838    _method_command("layer_add", _("&Add Layer..."), "AddLayer",
839                    helptext = _("Add a new layer to active map"))
840    _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
841                    helptext = _("Remove selected layer(s)"),
842                    sensitive = _can_remove_layer)
843    
844  # Layer menu  # Layer menu
845  _method_command("layer_add", "&Add", "AddLayer",  _method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
                 helptext = "Add a new layer to active map")  
 _method_command("layer_remove", "&Remove", "RemoveLayer",  
                 helptext = "Remove selected layer(s)",  
846                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
847  _method_command("layer_fill_color", "&Fill Color", "LayerFillColor",  _method_command("layer_raise", _("&Raise"), "RaiseLayer",
848                  helptext = "Set the fill color of selected layer(s)",                  helptext = _("Raise selected layer(s)"),
849                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
850  _method_command("layer_transparent_fill", "&Transparent Fill",  _method_command("layer_lower", _("&Lower"), "LowerLayer",
851                  "LayerTransparentFill",                  helptext = _("Lower selected layer(s)"),
                 helptext = "Do not fill the selected layer(s)",  
852                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
853  _method_command("layer_ourline_color", "&Outline Color", "LayerOutlineColor",  _method_command("layer_show", _("&Show"), "ShowLayer",
854                  helptext = "Set the outline color of selected layer(s)",                  helptext = _("Make selected layer(s) visible"),
855                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
856  _method_command("layer_no_outline", "&No Outline", "LayerNoOutline",  _method_command("layer_hide", _("&Hide"), "HideLayer",
857                  helptext = "Do not draw the outline of the selected layer(s)",                  helptext = _("Make selected layer(s) unvisible"),
858                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
859  _method_command("layer_raise", "&Raise", "RaiseLayer",  _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
860                  helptext = "Raise selected layer(s)",                  helptext = _("Show the selected layer's table"),
861                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
862  _method_command("layer_lower", "&Lower", "LowerLayer",  _method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
                 helptext = "Lower selected layer(s)",  
863                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
864  _method_command("layer_show", "&Show", "ShowLayer",  _method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
                 helptext = "Make selected layer(s) visible",  
865                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
866  _method_command("layer_hide", "&Hide", "HideLayer",  _method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
                 helptext = "Make selected layer(s) unvisible",  
                 sensitive = _has_selected_layer)  
 _method_command("layer_show_table", "Show Ta&ble", "LayerShowTable",  
                 helptext = "Show the selected layer's table",  
867                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
868    
869    # Table menu
870    _method_command("table_open", _("&Open..."), "TableOpen")
871    _method_command("table_close", _("&Close"), "TableClose")
872    _method_command("table_show", _("&Show"), "TableShow")
873    _method_command("table_hide", _("&Hide"), "TableHide")
874    _method_command("table_join", _("&Join..."), "TableJoin")
875    
876    #  Export only under Windows ...
877    map_menu = ["layer_add", "layer_remove", "map_rename",
878                            None,
879                            "map_projection",
880                            None,
881                            "map_zoom_in_tool", "map_zoom_out_tool",
882                            "map_pan_tool",
883                            "map_full_extent",
884                            "layer_full_extent",
885                            "selected_full_extent",
886                            None,
887                            "map_identify_tool", "map_label_tool",
888                            None,
889                            "toggle_legend",
890                            None]
891    if wxPlatform == '__WXMSW__':
892        map_menu.append("map_export")
893    map_menu.append("map_print")
894    
895    # the menu structure
896    main_menu = Menu("<main>", "<main>",
897                     [Menu("file", _("&File"),
898                           ["new_session", "open_session", None,
899                            "save_session", "save_session_as", None,
900                            "toggle_session_tree", None,
901                            "exit"]),
902                      Menu("map", _("&Map"), map_menu),
903                      Menu("layer", _("&Layer"),
904                            ["layer_raise", "layer_lower",
905                            None,
906                            "layer_show", "layer_hide",
907                            None,
908                            "layer_projection",
909                            None,
910                            "layer_show_table",
911                            "layer_jointable",
912                            "layer_unjointable",
913                            None,
914                            "layer_properties"]),
915                      Menu("table", _("&Table"),
916                           ["table_open", "table_close",
917                           None,
918                           "table_show", "table_hide",
919                           None,
920                           "table_join"]),
921                      Menu("help", _("&Help"),
922                           ["help_about"])])
923    
924    # the main toolbar
925    
926    main_toolbar = Menu("<toolbar>", "<toolbar>",
927                        ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
928                         "map_full_extent",
929                         "layer_full_extent",
930                         "selected_full_extent",
931                         None,
932                         "map_identify_tool", "map_label_tool"])

Legend:
Removed from v.37  
changed lines
  Added in v.923

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26