/[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 563 - (hide annotations)
Wed Mar 26 11:07:02 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 32852 byte(s)
Added sash windows to the main window and supporting functions for
manipulating the sashes.
(MainWindow.ShowLegend): Create a DockableWindow with the LegendPanel as the
contents.

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