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

Legend:
Removed from v.110  
changed lines
  Added in v.879

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26