/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/mainwindow.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/mainwindow.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1037 - (hide annotations)
Mon May 26 17:30:43 2003 UTC (21 years, 9 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 36953 byte(s)
(MainWindow.TableOpen): Real
implementation. Mark parts of the file format strings for
localization.

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

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26