/[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 84 by bh, Wed Apr 3 15:21:46 2002 UTC revision 563 by jonathan, Wed Mar 26 11:07:02 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]>
# Line 12  The main window Line 12  The main window
12    
13  __version__ = "$Revision$"  __version__ = "$Revision$"
14    
15  import sys, os  __ThubanVersion__ = "0.2" #"$THUBAN_0_2$"
16    #__BuildDate__ = "$Date$"
17    
18    import os
19    
20  from wxPython.wx import *  from wxPython.wx import *
21    
22  import Thuban  import Thuban
23  from Thuban.Model.session import Session, create_empty_session  from Thuban import _
24  from Thuban.Model.map import Map  from Thuban.Model.session import create_empty_session
25  from Thuban.Model.layer import Layer  from Thuban.Model.layer import Layer
26  from Thuban.Model.color import Color  from Thuban.Model.color import Color
27  from Thuban.Model.proj import Projection  from Thuban.Model.proj import Projection
# Line 27  import view Line 30  import view
30  import tree  import tree
31  import proj4dialog  import proj4dialog
32  import tableview, identifyview  import tableview, identifyview
33    import classifier
34    import legend
35    from menu import Menu
36    
37    from context import Context
38    from command import registry, Command, ToolCommand
39    from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION, DOCKABLE_DOCKED, DOCKABLE_UNDOCKED, DOCKABLE_CLOSED
40    
41  import main  from Thuban.UI.dock import DockableWindow
 from command import registry, Command  
 from messages import SELECTED_SHAPE  
42    
43    
44  # the directory where the toolbar icons are stored  # the directory where the toolbar icons are stored
45  bitmapdir = os.path.join(Thuban.__path__[0], os.pardir, "Resources", "Bitmaps")  bitmapdir = os.path.join(Thuban.__path__[0], os.pardir, "Resources", "Bitmaps")
46  bitmapext = ".xpm"  bitmapext = ".xpm"
47    
48    ID_WINDOW_LEGEND = 4001
49    ID_WINDOW_CANVAS = 4002
50    
51    
52  class MainWindow(wxFrame):  class MainWindow(wxFrame):
53    
54      def __init__(self, parent, ID, interactor):      # Some messages that can be subscribed/unsubscribed directly through
55          wxFrame.__init__(self, parent, ID, 'Thuban',      # the MapCanvas come in fact from other objects. This is a map to
56                           wxDefaultPosition, wxSize(400, 300))      # map those messages to the names of the instance variables they
57        # actually come from. This delegation is implemented in the
58        # Subscribe and unsubscribed methods
59        delegated_messages = {LAYER_SELECTED: "canvas",
60                              SHAPES_SELECTED: "canvas"}
61    
62        # Methods delegated to some instance variables. The delegation is
63        # implemented in the __getattr__ method.
64        delegated_methods = {"SelectLayer": "canvas",
65                             "SelectShapes": "canvas",
66                             }
67    
68        def __init__(self, parent, ID, title, application, interactor,
69                     initial_message = None, size = wxSize(-1, -1)):
70            wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
71    
72          self.interactor = interactor          self.application = application
73    
74          self.CreateStatusBar()          self.CreateStatusBar()
75          self.SetStatusText("This is the wxPython-based "          if initial_message:
76                        "Graphical User Interface for exploring geographic data")              self.SetStatusText(initial_message)
77    
78          self.identify_view = None          self.identify_view = None
79    
80          self.init_ids()          self.init_ids()
81    
82          menuBar = wxMenuBar()          # creat the menubar from the main_menu description
83            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 ["layer_add", "layer_remove",  
                      None,  
                      "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_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)  
84    
85          # toolbar          # Similarly, create the toolbar from main_toolbar
86          toolbar = self.CreateToolBar(wxTB_3DBUTTONS)          toolbar = self.build_toolbar(main_toolbar)
   
         # set the size of the tools' bitmaps. Not needed on wxGTK, but  
         # on Windows. We probably shouldn't hardwire the bitmap size  
         # here  
         toolbar.SetToolBitmapSize(wxSize(24, 24))  
   
         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)  
87          # call Realize to make sure that the tools appear.          # call Realize to make sure that the tools appear.
88          toolbar.Realize()          toolbar.Realize()
89    
90            win = wxSashLayoutWindow(self, ID_WINDOW_LEGEND,
91                                     style=wxNO_BORDER|wxSW_3D)
92            win.SetOrientation(wxLAYOUT_VERTICAL)
93            win.SetAlignment(wxLAYOUT_LEFT)
94            win.SetSashVisible(wxSASH_RIGHT, True)
95            win.SetSashBorder(wxSASH_RIGHT, True)
96            win.Hide()
97            self.sash_legend = win
98    
99    
100          # Create the map canvas          # Create the map canvas
101          canvas = view.MapCanvas(self, -1, interactor)          canvas = view.MapCanvas(self, -1)
102            canvas.Subscribe(VIEW_POSITION, self.view_position_changed)
103            canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
104          self.canvas = canvas          self.canvas = 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.legendPanel = None
111            self.legendWindow = None
112    
113    
114    
115          EVT_CLOSE(self, self.OnClose)          EVT_CLOSE(self, self.OnClose)
116            EVT_SASH_DRAGGED_RANGE(self,
117                ID_WINDOW_LEGEND, ID_WINDOW_CANVAS,
118                self._OnSashDrag)
119            EVT_SIZE(self, self._OnSize)
120    
121        def Subscribe(self, channel, *args):
122            """Subscribe a function to a message channel.
123    
124            If channel is one of the delegated messages call the appropriate
125            object's Subscribe method. Otherwise do nothing.
126            """
127            if channel in self.delegated_messages:
128                object = getattr(self, self.delegated_messages[channel])
129                object.Subscribe(channel, *args)
130            else:
131                print "Trying to subscribe to unsupported channel %s" % channel
132    
133        def Unsubscribe(self, channel, *args):
134            """Unsubscribe a function from a message channel.
135    
136            If channel is one of the delegated messages call the appropriate
137            object's Unsubscribe method. Otherwise do nothing.
138            """
139            if channel in self.delegated_messages:
140                object = getattr(self, self.delegated_messages[channel])
141                object.Unsubscribe(channel, *args)
142    
143        def __getattr__(self, attr):
144            """If attr is one of the delegated methods return that method
145    
146            Otherwise raise AttributeError.
147            """
148            if attr in self.delegated_methods:
149                return getattr(getattr(self, self.delegated_methods[attr]), attr)
150            raise AttributeError(attr)
151    
152      def init_ids(self):      def init_ids(self):
153          """Initialize the ids"""          """Initialize the ids"""
154          self.current_id = 6000          self.current_id = 6000
155          self.id_to_name = {}          self.id_to_name = {}
156          self.name_to_id = {}          self.name_to_id = {}
157            self.events_bound = {}
158    
159      def get_id(self, name):      def get_id(self, name):
160          """Return the wxWindows id for the command named name.          """Return the wxWindows id for the command named name.
# Line 136  class MainWindow(wxFrame): Line 167  class MainWindow(wxFrame):
167              self.name_to_id[name] = ID              self.name_to_id[name] = ID
168              self.id_to_name[ID] = name              self.id_to_name[ID] = name
169          return ID          return ID
170            
171        def bind_command_events(self, command, ID):
172            """Bind the necessary events for the given command and ID"""
173            if not self.events_bound.has_key(ID):
174                # the events haven't been bound yet
175                EVT_MENU(self, ID, self.invoke_command)
176                if command.IsDynamic():
177                    EVT_UPDATE_UI(self, ID, self.update_command_ui)
178    
179        def build_menu_bar(self, menudesc):
180            """Build and return the menu bar from the menu description"""
181            menu_bar = wxMenuBar()
182    
183            for item in menudesc.items:
184                # here the items must all be Menu instances themselves
185                menu_bar.Append(self.build_menu(item), item.title)
186    
187            return menu_bar
188    
189        def build_menu(self, menudesc):
190            """Return a wxMenu built from the menu description menudesc"""
191            wxmenu = wxMenu()
192            last = None
193            for item in menudesc.items:
194                if item is None:
195                    # a separator. Only add one if the last item was not a
196                    # separator
197                    if last is not None:
198                        wxmenu.AppendSeparator()
199                elif isinstance(item, Menu):
200                    # a submenu
201                    wxmenu.AppendMenu(wxNewId(), item.title, self.build_menu(item))
202                else:
203                    # must the name the name of a command
204                    self.add_menu_command(wxmenu, item)
205                last = item
206            return wxmenu
207    
208        def build_toolbar(self, toolbardesc):
209            """Build and return the main toolbar window from a toolbar description
210    
211            The parameter should be an instance of the Menu class but it
212            should not contain submenus.
213            """
214            toolbar = self.CreateToolBar(wxTB_3DBUTTONS)
215    
216            # set the size of the tools' bitmaps. Not needed on wxGTK, but
217            # on Windows, although it doesn't work very well there. It seems
218            # that only 16x16 icons are really supported on windows.
219            # We probably shouldn't hardwire the bitmap size here.
220            toolbar.SetToolBitmapSize(wxSize(24, 24))
221    
222            for item in toolbardesc.items:
223                if item is None:
224                    toolbar.AddSeparator()
225                else:
226                    # assume it's a string.
227                    self.add_toolbar_command(toolbar, item)
228    
229            return toolbar
230    
231      def add_menu_command(self, menu, name):      def add_menu_command(self, menu, name):
232          """Add the command with name name to the menu menu.          """Add the command with name name to the menu menu.
233    
# Line 150  class MainWindow(wxFrame): Line 241  class MainWindow(wxFrame):
241                  ID = self.get_id(name)                  ID = self.get_id(name)
242                  menu.Append(ID, command.Title(), command.HelpText(),                  menu.Append(ID, command.Title(), command.HelpText(),
243                              command.IsCheckCommand())                              command.IsCheckCommand())
244                  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)  
245              else:              else:
246                  print "Unknown command %s" % name                  print _("Unknown command %s") % name
247    
248      def add_toolbar_command(self, toolbar, name):      def add_toolbar_command(self, toolbar, name):
249          """Add the command with name name to the toolbar toolbar.          """Add the command with name name to the toolbar toolbar.
# Line 174  class MainWindow(wxFrame): Line 263  class MainWindow(wxFrame):
263                  toolbar.AddTool(ID, bitmap,                  toolbar.AddTool(ID, bitmap,
264                                  shortHelpString = command.HelpText(),                                  shortHelpString = command.HelpText(),
265                                  isToggle = command.IsCheckCommand())                                  isToggle = command.IsCheckCommand())
266                    self.bind_command_events(command, ID)
267              else:              else:
268                  print "Unknown command %s" % name                  print _("Unknown command %s") % name
269    
270        def Context(self):
271            """Return the context object for a command invoked from this window
272            """
273            return Context(self.application, self.application.Session(), self)
274    
275      def invoke_command(self, event):      def invoke_command(self, event):
276          name = self.id_to_name.get(event.GetId())          name = self.id_to_name.get(event.GetId())
277          if name is not None:          if name is not None:
278              command = registry.Command(name)              command = registry.Command(name)
279              command.Execute(self)              command.Execute(self.Context())
280          else:          else:
281              print "Unknown command ID %d" % event.GetId()              print _("Unknown command ID %d") % event.GetId()
282    
283      def update_command_ui(self, event):      def update_command_ui(self, event):
284          #print "update_command_ui", self.id_to_name[event.GetId()]          #print "update_command_ui", self.id_to_name[event.GetId()]
285            context = self.Context()
286          command = registry.Command(self.id_to_name[event.GetId()])          command = registry.Command(self.id_to_name[event.GetId()])
287          if command is not None:          if command is not None:
288              event.Enable(command.Sensitive(self))              sensitive = command.Sensitive(context)
289              event.SetText(command.DynText(self))              event.Enable(sensitive)
290                if command.IsTool() and not sensitive and command.Checked(context):
291                    # When a checked tool command is disabled deselect all
292                    # tools. Otherwise the tool would remain active but it
293                    # might lead to errors if the tools stays active. This
294                    # problem occurred in GREAT-ER and this fixes it, but
295                    # it's not clear to me whether this is really the best
296                    # way to do it (BH, 20021206).
297                    self.canvas.SelectTool(None)
298                event.SetText(command.DynText(context))
299              if command.IsCheckCommand():              if command.IsCheckCommand():
300                  event.Check(command.Checked(self))                      event.Check(command.Checked(context))
301    
302      def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):      def RunMessageBox(self, title, text, flags = wxOK | wxICON_INFORMATION):
303          """Run a modla message box with the given text, title and flags          """Run a modal message box with the given text, title and flags
304          and return the result"""          and return the result"""
305          dlg = wxMessageDialog(self, text, title, flags)          dlg = wxMessageDialog(self, text, title, flags)
306            dlg.CenterOnParent()
307          result = dlg.ShowModal()          result = dlg.ShowModal()
308          dlg.Destroy()          dlg.Destroy()
309          return result          return result
# Line 211  class MainWindow(wxFrame): Line 317  class MainWindow(wxFrame):
317    
318      def add_dialog(self, name, dialog):      def add_dialog(self, name, dialog):
319          if self.dialogs.has_key(name):          if self.dialogs.has_key(name):
320              raise RuntimeError("The Dialog named %s is already open" % name)              raise RuntimeError(_("The Dialog named %s is already open") % name)
321          self.dialogs[name] = dialog          self.dialogs[name] = dialog
322    
323      def dialog_open(self, name):      def dialog_open(self, name):
# Line 223  class MainWindow(wxFrame): Line 329  class MainWindow(wxFrame):
329      def get_open_dialog(self, name):      def get_open_dialog(self, name):
330          return self.dialogs.get(name)          return self.dialogs.get(name)
331    
332        def view_position_changed(self):
333            pos = self.canvas.CurrentPosition()
334            if pos is not None:
335                text = "(%10.10g, %10.10g)" % pos
336            else:
337                text = ""
338            self.set_position_text(text)
339    
340        def set_position_text(self, text):
341            """Set the statusbar text showing the current position.
342    
343            By default the text is shown in field 0 of the status bar.
344            Override this method in derived classes to put it into a
345            different field of the statusbar.
346            """
347            self.SetStatusText(text)
348    
349      def save_modified_session(self, can_veto = 1):      def save_modified_session(self, can_veto = 1):
350          """If the current session has been modified, ask the user          """If the current session has been modified, ask the user
351          whether to save it and do so if requested. Return the outcome of          whether to save it and do so if requested. Return the outcome of
# Line 232  class MainWindow(wxFrame): Line 355  class MainWindow(wxFrame):
355          If the can_veto parameter is true (default) the dialog includes          If the can_veto parameter is true (default) the dialog includes
356          a cancel button, otherwise not.          a cancel button, otherwise not.
357          """          """
358          if main.app.session.WasModified():          if self.application.session.WasModified():
359              flags = wxYES_NO | wxICON_QUESTION              flags = wxYES_NO | wxICON_QUESTION
360              if can_veto:              if can_veto:
361                  flags = flags | wxCANCEL                  flags = flags | wxCANCEL
362              result = self.RunMessageBox("Exit",              result = self.RunMessageBox(_("Exit"),
363                                          ("The session has been modified."                                          _("The session has been modified."
364                                           " Do you want to save it?"),                                           " Do you want to save it?"),
365                                          flags)                                          flags)
366              if result == wxID_YES:              if result == wxID_YES:
# Line 246  class MainWindow(wxFrame): Line 369  class MainWindow(wxFrame):
369              result = wxID_NO              result = wxID_NO
370          return result          return result
371    
372        def prepare_new_session(self):
373            for d in self.dialogs.values():
374                if not isinstance(d, tree.SessionTreeView):
375                    d.Close()
376    
377      def NewSession(self):      def NewSession(self):
378          self.save_modified_session()          self.save_modified_session()
379          main.app.SetSession(create_empty_session())          self.prepare_new_session()
380            self.application.SetSession(create_empty_session())
381    
382      def OpenSession(self):      def OpenSession(self):
383          self.save_modified_session()          self.save_modified_session()
384          dlg = wxFileDialog(self, "Select a session file", ".", "",          dlg = wxFileDialog(self, _("Open Session"), ".", "", "*.thuban", wxOPEN)
                            "*.session", wxOPEN)  
385          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
386              main.app.OpenSession(dlg.GetPath())              self.prepare_new_session()
387                self.application.OpenSession(dlg.GetPath())
388          dlg.Destroy()          dlg.Destroy()
389    
390      def SaveSession(self):      def SaveSession(self):
391          main.app.SaveSession()          if self.application.session.filename == None:
392                self.SaveSessionAs()
393            else:
394                self.application.SaveSession()
395    
396      def SaveSessionAs(self):      def SaveSessionAs(self):
397          dlg = wxFileDialog(self, "Enter a filename for session", ".", "",          dlg = wxFileDialog(self, _("Save Session As"), ".", "",
398                             "*.session", wxOPEN)                             "*.thuban", wxOPEN)
399          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
400              main.app.session.SetFilename(dlg.GetPath())              self.application.session.SetFilename(dlg.GetPath())
401              main.app.SaveSession()              self.application.SaveSession()
402          dlg.Destroy()          dlg.Destroy()
403    
404      def Exit(self):      def Exit(self):
# Line 277  class MainWindow(wxFrame): Line 409  class MainWindow(wxFrame):
409          if result == wxID_CANCEL:          if result == wxID_CANCEL:
410              event.Veto()              event.Veto()
411          else:          else:
412                # FIXME: it would be better to tie the unsubscription to
413                # wx's destroy event, but that isn't implemented for wxGTK
414                # yet.
415                self.canvas.Unsubscribe(VIEW_POSITION, self.view_position_changed)
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.legendPanel.SetMap(map)
421    
422        def Map(self):
423            """Return the map displayed by this mainwindow"""
424    
425            # sanity check
426            #assert(self.canvas.Map() is self.legendPanel.GetMap())
427    
428            return self.canvas.Map()
429    
430      def ShowSessionTree(self):      def ShowSessionTree(self):
431          name = "session_tree"          name = "session_tree"
432          dialog = self.get_open_dialog(name)          dialog = self.get_open_dialog(name)
433          if dialog is None:          if dialog is None:
434              dialog = tree.SessionTreeView(self, main.app, name)              dialog = tree.SessionTreeView(self, self.application, name)
435              self.add_dialog(name, dialog)              self.add_dialog(name, dialog)
436              dialog.Show(true)              dialog.Show(True)
437          else:          else:
438              # FIXME: bring dialog to front here              # FIXME: bring dialog to front here
439              pass              pass
440    
441    
442      def About(self):      def About(self):
443          self.RunMessageBox("About",          self.RunMessageBox(_("About"),
444                             ("Thuban is a program for\n"                             _("Thuban v%s\n"
445                                #"Build Date: %s\n"
446                                "\n"
447                                "Thuban is a program for\n"
448                              "exploring geographic data.\n"                              "exploring geographic data.\n"
449                              "Copyright (C) 2001 Intevation GmbH.\n"                              "Copyright (C) 2001-2003 Intevation GmbH.\n"
450                              "Thuban is licensed under the GPL"),                              "Thuban is licensed under the GNU GPL"
451                               % __ThubanVersion__), #__BuildDate__)),
452                             wxOK | wxICON_INFORMATION)                             wxOK | wxICON_INFORMATION)
453    
454      def AddLayer(self):      def AddLayer(self):
455          dlg = wxFileDialog(self, "Select a session file", ".", "", "*.*",          dlg = wxFileDialog(self, _("Select a data file"), ".", "", "*.*",
456                             wxOPEN)                             wxOPEN)
457          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wxID_OK:
458              filename = dlg.GetPath()              filename = dlg.GetPath()
# Line 314  class MainWindow(wxFrame): Line 464  class MainWindow(wxFrame):
464                  map.AddLayer(layer)                  map.AddLayer(layer)
465              except IOError:              except IOError:
466                  # the layer couldn't be opened                  # the layer couldn't be opened
467                  self.RunMessageBox("Add Layer",                  self.RunMessageBox(_("Add Layer"),
468                                     "Can't open the file '%s'." % filename)                                     _("Can't open the file '%s'.") % filename)
469              else:              else:
470                  if not has_layers:                  if not has_layers:
471                      # if we're adding a layer to an empty map, for the                      # if we're adding a layer to an empty map, fit the
472                      # new map to the window                      # new map to the window
473                      self.canvas.FitMapToWindow()                      self.canvas.FitMapToWindow()
474          dlg.Destroy()          dlg.Destroy()
# Line 328  class MainWindow(wxFrame): Line 478  class MainWindow(wxFrame):
478          if layer is not None:          if layer is not None:
479              self.canvas.Map().RemoveLayer(layer)              self.canvas.Map().RemoveLayer(layer)
480    
481        def CanRemoveLayer(self):
482            """Return true if the currently selected layer can be deleted.
483    
484            If no layer is selected return false.
485    
486            The return value of this method determines whether the remove
487            layer command is sensitive in menu.
488            """
489            layer = self.current_layer()
490            if layer is not None:
491                return self.canvas.Map().CanRemoveLayer(layer)
492            return 0
493    
494      def RaiseLayer(self):      def RaiseLayer(self):
495          layer = self.current_layer()          layer = self.current_layer()
496          if layer is not None:          if layer is not None:
497              self.canvas.Map().RaiseLayer(layer)              self.canvas.Map().RaiseLayer(layer)
498            
499      def LowerLayer(self):      def LowerLayer(self):
500          layer = self.current_layer()          layer = self.current_layer()
501          if layer is not None:          if layer is not None:
# Line 343  class MainWindow(wxFrame): Line 506  class MainWindow(wxFrame):
506    
507          If no layer is selected, return None          If no layer is selected, return None
508          """          """
509          return self.interactor.SelectedLayer()          return self.canvas.SelectedLayer()
510    
511      def has_selected_layer(self):      def has_selected_layer(self):
512          """Return true if a layer is currently selected"""          """Return true if a layer is currently selected"""
513          return self.interactor.HasSelectedLayer()          return self.canvas.HasSelectedLayer()
514    
515      def choose_color(self):      def choose_color(self):
516          """Run the color selection dialog and return the selected color.          """Run the color selection dialog and return the selected color.
# Line 370  class MainWindow(wxFrame): Line 533  class MainWindow(wxFrame):
533          if layer is not None:          if layer is not None:
534              color = self.choose_color()              color = self.choose_color()
535              if color is not None:              if color is not None:
536                  layer.SetFill(color)                  layer.GetClassification().SetDefaultFill(color)
537    
538      def LayerTransparentFill(self):      def LayerTransparentFill(self):
539          layer = self.current_layer()          layer = self.current_layer()
540          if layer is not None:          if layer is not None:
541              layer.SetFill(None)              layer.GetClassification().SetDefaultFill(Color.None)
542    
543      def LayerOutlineColor(self):      def LayerOutlineColor(self):
544          layer = self.current_layer()          layer = self.current_layer()
545          if layer is not None:          if layer is not None:
546              color = self.choose_color()              color = self.choose_color()
547              if color is not None:              if color is not None:
548                  layer.SetStroke(color)                  layer.GetClassification().SetDefaultLineColor(color)
549    
550      def LayerNoOutline(self):      def LayerNoOutline(self):
551          layer = self.current_layer()          layer = self.current_layer()
552          if layer is not None:          if layer is not None:
553              layer.SetStroke(None)              layer.GetClassification().SetDefaultLineColor(Color.None)
554    
555      def HideLayer(self):      def HideLayer(self):
556          layer = self.current_layer()          layer = self.current_layer()
# Line 406  class MainWindow(wxFrame): Line 569  class MainWindow(wxFrame):
569              name = "table_view" + str(id(table))              name = "table_view" + str(id(table))
570              dialog = self.get_open_dialog(name)              dialog = self.get_open_dialog(name)
571              if dialog is None:              if dialog is None:
572                  dialog = tableview.TableFrame(self, self.interactor, name,                  dialog = tableview.LayerTableFrame(self, name,
573                                                "Table: %s" % layer.Title(),                                                 _("Table: %s") % layer.Title(),
574                                                layer, table)                                                     layer, table)
575                  self.add_dialog(name, dialog)                  self.add_dialog(name, dialog)
576                  dialog.Show(true)                  dialog.Show(true)
577              else:              else:
# Line 419  class MainWindow(wxFrame): Line 582  class MainWindow(wxFrame):
582          map = self.canvas.Map()          map = self.canvas.Map()
583          proj = map.projection          proj = map.projection
584          if proj is None:          if proj is None:
585              proj4Dlg = proj4dialog.Proj4Dialog(NULL, None)              proj4Dlg = proj4dialog.Proj4Dialog(NULL, None, map.BoundingBox())
586          else:          else:
587              proj4Dlg = proj4dialog.Proj4Dialog(NULL, map.projection.params)              proj4Dlg = proj4dialog.Proj4Dialog(NULL, map.projection.params,
588                                                   map.BoundingBox())
589          if proj4Dlg.ShowModal() == wxID_OK:          if proj4Dlg.ShowModal() == wxID_OK:
590              params = proj4Dlg.GetParams()              params = proj4Dlg.GetParams()
591              if params is not None:              if params is not None:
# Line 431  class MainWindow(wxFrame): Line 595  class MainWindow(wxFrame):
595              map.SetProjection(proj)              map.SetProjection(proj)
596          proj4Dlg.Destroy()          proj4Dlg.Destroy()
597    
598        def Classify(self):
599    
600            #
601            # the menu option for this should only be available if there
602            # is a current layer, so we don't need to check if the
603            # current layer is None
604            #
605    
606            layer = self.current_layer()
607            self.OpenClassifier(layer)
608    
609        def OpenClassifier(self, layer):
610            name = "classifier" + str(id(layer))
611            dialog = self.get_open_dialog(name)
612    
613            if dialog is None:
614                dialog = classifier.Classifier(self, name, layer)
615                self.add_dialog(name, dialog)
616                dialog.Show()
617    
618    
619        def ShowLegend(self, switch = False):
620            
621            name = "legend"
622            dialog = self.get_open_dialog(name)
623    
624            if dialog is None:
625                self.legendPanel = \
626                    legend.LegendPanel(self.sash_legend, None, self)
627                dialog = DockableWindow(self, -1, name,
628                                        "Legend: %s" % self.Map().Title(),
629                                        self.sash_legend, self.legendPanel)
630    
631    
632                self.add_dialog(name, dialog)
633    
634                dialog.Subscribe(DOCKABLE_DOCKED, self._OnLegendDock)
635                dialog.Subscribe(DOCKABLE_UNDOCKED, self._OnLegendUnDock)
636                dialog.Subscribe(DOCKABLE_CLOSED, self._OnLegendClosed)
637    
638                self.legendWindow = dialog
639                self.legendPanel.SetMap(self.Map())
640    
641            dialog.Show()
642    
643      def ZoomInTool(self):      def ZoomInTool(self):
644          self.canvas.ZoomInTool()          self.canvas.ZoomInTool()
645    
# Line 453  class MainWindow(wxFrame): Line 662  class MainWindow(wxFrame):
662      def PrintMap(self):      def PrintMap(self):
663          self.canvas.Print()          self.canvas.Print()
664    
665      def identify_view_on_demand(self, layer, shape):      def identify_view_on_demand(self, layer, shapes):
666          name = "identify_view"          name = "identify_view"
667          if self.canvas.CurrentTool() == "IdentifyTool":          if self.canvas.CurrentTool() == "IdentifyTool":
668              if not self.dialog_open(name):              if not self.dialog_open(name):
669                  dialog = identifyview.IdentifyView(self, self.interactor, name)                  dialog = identifyview.IdentifyView(self, name)
670                  self.add_dialog(name, dialog)                  self.add_dialog(name, dialog)
671                  dialog.Show(true)                  dialog.Show(True)
672              else:              else:
673                  # FIXME: bring dialog to front?                  # FIXME: bring dialog to front?
674                  pass                  pass
675    
676    
677        def _OnSashDrag(self, event):
678    
679            if event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE:
680                return
681    
682            id = event.GetId()
683    
684            rect = event.GetDragRect()
685    
686            if id == ID_WINDOW_LEGEND:
687                #assert(self.legendPanel.IsDocked())
688                assert(self.legendWindow.IsDocked())
689                #assert(self.legendPanel.GetParent() is self.sash_legend)
690                self.__SetLegendDockSize(rect)
691    
692            wxLayoutAlgorithm().LayoutWindow(self, self.canvas)
693    
694        def _OnSize(self, event):
695            wxLayoutAlgorithm().LayoutWindow(self, self.canvas)
696    
697        def _OnLegendDock(self, id, win):
698            if not self.sash_legend.IsShown():
699                self.sash_legend.Show()
700                self.__SetLegendDockSize(None)
701                wxLayoutAlgorithm().LayoutWindow(self, self.canvas)
702    
703        def _OnLegendUnDock(self, id, win):
704            if self.sash_legend.IsShown():
705                self.sash_legend.Hide()
706                wxLayoutAlgorithm().LayoutWindow(self, self.canvas)
707    
708        def _OnLegendClosed(self, id, win):
709            if self.sash_legend.IsShown():
710                self.sash_legend.Hide()
711                wxLayoutAlgorithm().LayoutWindow(self, self.canvas)
712    
713        def __SetLegendDockSize(self, rect):
714        
715            w, h = self.legendWindow.GetBestSize()
716            #w, h = self.legendPanel.GetBestSize()
717    
718            if rect is not None:
719                rw = rect.width
720                rh = rect.height
721                if rw < w: rw = w
722            else:
723                rw = w
724                rh = h
725    
726            rw += 2 # XXX: without this the sash isn't visible!?!?!?!
727    
728            self.sash_legend.SetDefaultSize(wxSize(rw, 1000))
729    
730  #  #
731  # Define all the commands available in the main window  # Define all the commands available in the main window
732  #  #
# Line 471  class MainWindow(wxFrame): Line 734  class MainWindow(wxFrame):
734    
735  # Helper functions to define common command implementations  # Helper functions to define common command implementations
736  def call_method(context, methodname, *args):  def call_method(context, methodname, *args):
737      """Call the context's method methodname with args *args"""      """Call the mainwindow's method methodname with args *args"""
738      apply(getattr(context, methodname), args)      apply(getattr(context.mainwindow, methodname), args)
739    
740  def _method_command(name, title, method, helptext = "", sensitive = None):  def _method_command(name, title, method, helptext = "",
741      """Add a command implemented by a method of the context object"""                      icon = "", sensitive = None):
742        """Add a command implemented by a method of the mainwindow object"""
743      registry.Add(Command(name, title, call_method, args=(method,),      registry.Add(Command(name, title, call_method, args=(method,),
744                           helptext = helptext, sensitive = sensitive))                           helptext = helptext, icon = icon,
745                             sensitive = sensitive))
746    
747    def make_check_current_tool(toolname):
748        """Return a function that tests if the currently active tool is toolname
749    
750        The returned function can be called with the context and returns
751        true iff the currently active tool's name is toolname. It's directly
752        usable as the 'checked' callback of a command.
753        """
754        def check_current_tool(context, name=toolname):
755            return context.mainwindow.canvas.CurrentTool() == name
756        return check_current_tool
757    
758  def _tool_command(name, title, method, toolname, helptext = "",  def _tool_command(name, title, method, toolname, helptext = "",
759                    icon = ""):                    icon = "", sensitive = None):
760      """Add a tool command"""      """Add a tool command"""
761      def check_current_tool(context, name=toolname):      registry.Add(ToolCommand(name, title, call_method, args=(method,),
762          return context.canvas.CurrentTool() == name                               helptext = helptext, icon = icon,
763      registry.Add(Command(name, title, call_method, args=(method,),                               checked = make_check_current_tool(toolname),
764                           helptext = helptext, icon = icon,                               sensitive = sensitive))
                          checked = check_current_tool))  
765    
766  def _has_selected_layer(context):  def _has_selected_layer(context):
767      """Return true if a layer is selected in the context"""      """Return true if a layer is selected in the context"""
768      return context.has_selected_layer()      return context.mainwindow.has_selected_layer()
769    
770    def _can_remove_layer(context):
771        return context.mainwindow.CanRemoveLayer()
772    
773    def _has_tree_window_shown(context):
774        """Return true if the tree window is shown"""
775        return context.mainwindow.get_open_dialog("session_tree") is None
776    
777    def _has_visible_map(context):
778        """Return true iff theres a visible map in the mainwindow.
779    
780        A visible map is a map with at least one visible layer."""
781        map = context.mainwindow.Map()
782        if map is not None:
783            for layer in map.Layers():
784                if layer.Visible():
785                    return 1
786        return 0
787    
788    def _has_legend_shown(context):
789        """Return true if the legend window is shown"""
790        return context.mainwindow.get_open_dialog("legend") is None
791    
792    
793  # File menu  # File menu
794  _method_command("new_session", "&New Session", "NewSession")  _method_command("new_session", _("&New Session"), "NewSession")
795  _method_command("open_session", "&Open Session", "OpenSession")  _method_command("open_session", _("&Open Session"), "OpenSession")
796  _method_command("save_session", "&Save Session", "SaveSession")  _method_command("save_session", _("&Save Session"), "SaveSession")
797  _method_command("save_session_as", "Save Session &As", "SaveSessionAs")  _method_command("save_session_as", _("Save Session &As"), "SaveSessionAs")
798  _method_command("exit", "&Exit", "Exit")  _method_command("show_session_tree", _("Show Session &Tree"), "ShowSessionTree",
799                    sensitive = _has_tree_window_shown)
800    _method_command("exit", _("E&xit"), "Exit")
801    
802  # Help menu  # Help menu
803  _method_command("help_about", "&About", "About")  _method_command("help_about", _("&About"), "About")
804    
805    
806  # Map menu  # Map menu
807  _method_command("map_projection", "Pro&jection", "Projection")  _method_command("map_projection", _("Pro&jection"), "Projection")
808    
809  _tool_command("map_zoom_in_tool", "&Zoom in", "ZoomInTool", "ZoomInTool",  _tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
810                helptext = "Switch to map-mode 'zoom-in'", icon = "zoom_in")                helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
811  _tool_command("map_zoom_out_tool", "Zoom &out", "ZoomOutTool", "ZoomOutTool",                sensitive = _has_visible_map)
812                helptext = "Switch to map-mode 'zoom-out'", icon = "zoom_out")  _tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
813  _tool_command("map_pan_tool", "&Pan", "PanTool", "PanTool",                helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
814                helptext = "Switch to map-mode 'pan'", icon = "pan")                sensitive = _has_visible_map)
815  _tool_command("map_identify_tool", "&Identify", "IdentifyTool", "IdentifyTool",  _tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
816                helptext = "Switch to map-mode 'identify'", icon = "identify")                helptext = _("Switch to map-mode 'pan'"), icon = "pan",
817  _tool_command("map_label_tool", "&Label", "LabelTool", "LabelTool",                sensitive = _has_visible_map)
818                helptext = "Add/Remove labels", icon = "label")  _tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
819  _method_command("map_full_extent", "&Full extent", "FullExtent")                "IdentifyTool",
820  _method_command("map_print", "Prin&t", "PrintMap", helptext = "Print the map")                helptext = _("Switch to map-mode 'identify'"), icon = "identify",
821                  sensitive = _has_visible_map)
822    _tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
823                  helptext = _("Add/Remove labels"), icon = "label",
824                  sensitive = _has_visible_map)
825    _method_command("map_full_extent", _("&Full extent"), "FullExtent",
826                   helptext = _("Full Extent"), icon = "fullextent",
827                  sensitive = _has_visible_map)
828    _method_command("map_print", _("Prin&t"), "PrintMap",
829                    helptext = _("Print the map"))
830    
831  # Layer menu  # Layer menu
832  _method_command("layer_add", "&Add Layer", "AddLayer",  _method_command("layer_add", _("&Add Layer"), "AddLayer",
833                  helptext = "Add a new layer to active map")                  helptext = _("Add a new layer to active map"))
834  _method_command("layer_remove", "&Remove Layer", "RemoveLayer",  _method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
835                  helptext = "Remove selected layer(s)",                  helptext = _("Remove selected layer(s)"),
836                    sensitive = _can_remove_layer)
837    _method_command("layer_fill_color", _("&Fill Color"), "LayerFillColor",
838                    helptext = _("Set the fill color of selected layer(s)"),
839                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
840  _method_command("layer_fill_color", "&Fill Color", "LayerFillColor",  _method_command("layer_transparent_fill", _("&Transparent Fill"),
                 helptext = "Set the fill color of selected layer(s)",  
                 sensitive = _has_selected_layer)  
 _method_command("layer_transparent_fill", "&Transparent Fill",  
841                  "LayerTransparentFill",                  "LayerTransparentFill",
842                  helptext = "Do not fill the selected layer(s)",                  helptext = _("Do not fill the selected layer(s)"),
843                    sensitive = _has_selected_layer)
844    _method_command("layer_outline_color", _("&Outline Color"), "LayerOutlineColor",
845                    helptext = _("Set the outline color of selected layer(s)"),
846                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
847  _method_command("layer_ourline_color", "&Outline Color", "LayerOutlineColor",  _method_command("layer_no_outline", _("&No Outline"), "LayerNoOutline",
848                  helptext = "Set the outline color of selected layer(s)",                  helptext= _("Do not draw the outline of the selected layer(s)"),
849                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
850  _method_command("layer_no_outline", "&No Outline", "LayerNoOutline",  _method_command("layer_raise", _("&Raise"), "RaiseLayer",
851                  helptext = "Do not draw the outline of the selected layer(s)",                  helptext = _("Raise selected layer(s)"),
852                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
853  _method_command("layer_raise", "&Raise", "RaiseLayer",  _method_command("layer_lower", _("&Lower"), "LowerLayer",
854                  helptext = "Raise selected layer(s)",                  helptext = _("Lower selected layer(s)"),
855                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
856  _method_command("layer_lower", "&Lower", "LowerLayer",  _method_command("layer_show", _("&Show"), "ShowLayer",
857                  helptext = "Lower selected layer(s)",                  helptext = _("Make selected layer(s) visible"),
858                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
859  _method_command("layer_show", "&Show", "ShowLayer",  _method_command("layer_hide", _("&Hide"), "HideLayer",
860                  helptext = "Make selected layer(s) visible",                  helptext = _("Make selected layer(s) unvisible"),
861                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
862  _method_command("layer_hide", "&Hide", "HideLayer",  _method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
863                  helptext = "Make selected layer(s) unvisible",                  helptext = _("Show the selected layer's table"),
864                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
865  _method_command("layer_show_table", "Show Ta&ble", "LayerShowTable",  _method_command("layer_classifier", _("Classify"), "Classify",
                 helptext = "Show the selected layer's table",  
866                  sensitive = _has_selected_layer)                  sensitive = _has_selected_layer)
867    _method_command("show_legend", _("Legend"), "ShowLegend",
868                    sensitive = _has_legend_shown)
869    
870    # the menu structure
871    main_menu = Menu("<main>", "<main>",
872                     [Menu("file", _("&File"),
873                           ["new_session", "open_session", None,
874                            "save_session", "save_session_as", None,
875                            "show_session_tree", None,
876                            "show_legend", None,
877                            "exit"]),
878                      Menu("map", _("&Map"),
879                           ["layer_add", "layer_remove",
880                            None,
881                            "map_projection",
882                            None,
883                            "map_zoom_in_tool", "map_zoom_out_tool",
884                            "map_pan_tool", "map_identify_tool", "map_label_tool",
885                            None,
886                            "map_full_extent",
887                            None,
888                            "map_print"]),
889                      Menu("layer", _("&Layer"),
890                           ["layer_fill_color", "layer_transparent_fill",
891                            "layer_outline_color", "layer_no_outline",
892                            None,
893                            "layer_raise", "layer_lower",
894                            None,
895                            "layer_show", "layer_hide",
896                            None,
897                            "layer_show_table",
898                            None,
899                            "layer_classifier"]),
900                      Menu("help", _("&Help"),
901                           ["help_about"])])
902    
903    # the main toolbar
904    
905    main_toolbar = Menu("<toolbar>", "<toolbar>",
906                        ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
907                         "map_full_extent", None,
908                         "map_identify_tool", "map_label_tool"])

Legend:
Removed from v.84  
changed lines
  Added in v.563

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26