/[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 1072 - (hide annotations)
Tue May 27 16:47:48 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: 37525 byte(s)
* Thuban/UI/join.py (JoinDialog): Extend to handle layer joins as
well
(JoinDialog.__init__): Use the layer parameter and only build the
left choice when a layer is given
(JoinDialog.OnJoin): Handle layer joins as well
(JoinDialog.OnLeftTable, JoinDialog.OnRightTable): Handle the case
that the user selects the "Select..." item. The sensitivitly
updating is now in update_sensitivity
(JoinDialog.y): New method to refactor the sensitivity update of
the join button into its own method.

* Thuban/UI/mainwindow.py (MainWindow.LayerJoinTable): Implement.

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