/[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 535 - (hide annotations)
Fri Mar 14 20:42:18 2003 UTC (21 years, 11 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/mainwindow.py
File MIME type: text/x-python
File size: 29197 byte(s)
Implement multiple selected shapes

* Thuban/UI/selection.py: New module with a class to represent the
selection.

* Thuban/UI/messages.py (SELECTED_TABLE, SELECTED_MAP): Remove
these unused messages

* Thuban/UI/application.py (ThubanApplication.OnInit)
(ThubanApplication.OnExit, ThubanApplication.SetSession): The
interactor is gone now.
(ThubanApplication.CreateMainWindow): There is no interactor
anymore so we pass None as the interactor argument for now for
compatibility.

* Thuban/UI/view.py (MapCanvas.delegated_messages)
(MapCanvas.Subscribe, MapCanvas.Unsubscribe): In Subscribe and
Unsubscribe, delegate messages according to the delegated_messages
class variable.
(MapCanvas.__getattr__, MapCanvas.delegated_methods): Get some
attributes from instance variables as described with the
delegated_methods class variable.
(MapCanvas.__init__): New instance variable selection holding the
current selection
(MapCanvas.do_redraw): Deal with multiple selected shapes. Simply
pass them on to the renderer
(MapCanvas.SetMap): Clear the selection when a different map is
selected.
(MapCanvas.shape_selected): Simple force a complete redraw. The
selection class now takes care of only issueing SHAPES_SELECTED
messages when the set of selected shapes actually does change.
(MapCanvas.SelectShapeAt): The selection is now managed in
self.selection

* Thuban/UI/mainwindow.py (MainWindow.delegated_messages)
(MainWindow.Subscribe, MainWindow.Unsubscribe): In Subscribe and
Unsubscribe, delegate messages according to the delegated_messages
class variable.
(MainWindow.delegated_methods, MainWindow.__getattr__): Get some
attributes from instance variables as described with the
delegated_methods class variable.
(MainWindow.__init__): The interactor as ivar is gone. The
parameter is still there for compatibility. The selection messages
now come from the canvas.
(MainWindow.current_layer, MainWindow.has_selected_layer):
Delegate to the the canvas.
(MainWindow.LayerShowTable, MainWindow.Classify)
(MainWindow.identify_view_on_demand): The dialogs don't need the
interactor parameter anymore.

* Thuban/UI/tableview.py (TableFrame.__init__)
(LayerTableFrame.__init__, LayerTableFrame.OnClose)
(LayerTableFrame.row_selected): The interactor is gone. It's job
from the dialog's point of view is now done by the mainwindow,
i.e. the parent. Subscribe to SHAPES_SELECTED instead
of SELECTED_SHAPE

* Thuban/UI/dialogs.py (NonModalDialog.__init__): The interactor
is gone. It's job from the dialog's point of view is now done by
the mainwindow, i.e. the parent.

* Thuban/UI/classifier.py (Classifier.__init__): The interactor is
gone. It's job from the dialog's point of view is now done by the
mainwindow, i.e. the parent.

* Thuban/UI/tree.py (SessionTreeView.__init__): The interactor is
gone. It's job from the dialog's point of view is now done by the
mainwindow, i.e. the parent.
(SessionTreeCtrl.__init__): New parameter mainwindow which is
stored as self.mainwindow. The mainwindow is need so that the tree
can still subscribe to the selection messages.
(SessionTreeCtrl.__init__, SessionTreeCtrl.unsubscribe_all)
(SessionTreeCtrl.update_tree, SessionTreeCtrl.OnSelChanged): The
selection is now accessible through the mainwindow. Subscribe to
SHAPES_SELECTED instead of SELECTED_SHAPE

* Thuban/UI/identifyview.py (IdentifyView.__init__): Use the
SHAPES_SELECTED message now.
(IdentifyView.selected_shape): Now subscribed to SHAPES_SELECTED,
so deal with multiple shapes
(IdentifyView.__init__, IdentifyView.OnClose): The interactor is
gone. It's job from the dialog's point of view is now done by the
mainwindow, i.e. the parent.

* Thuban/UI/renderer.py (ScreenRenderer.RenderMap): Rename the
selected_shape parameter and ivar to selected_shapes. It's now a
list of shape ids.
(MapRenderer.draw_label_layer): Deal with multiple selected
shapes. Rearrange the code a bit so that the setup and shape type
distinctions are only executed once.

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