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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2072 - (hide annotations)
Tue Feb 17 13:14:49 2004 UTC (21 years ago) by bh
Original Path: trunk/thuban/Thuban/UI/application.py
File MIME type: text/x-python
File size: 11802 byte(s)
Fix for RT#2245

* Thuban/UI/application.py (ThubanApplication.OnInit): Initialize
instance variables before trying to create any windows.  Creating
windows can start an event loop if e.g. message boxes are popped
up for some reason, and event handlers, especially EVT_UPDATE_UI
may want to access things from the application.
(ThubanApplication.maps_changed): The mainwindow may not have been
created yet, so check whether it has been created before calling
its methods

* Thuban/UI/view.py (MapCanvas.OnIdle): Only try to redraw if we
have a map

1 bh 2072 # Copyright (C) 2001, 2002, 2003, 2004 by Intevation GmbH
2 bh 6 # Authors:
3     # Jan-Oliver Wagner <[email protected]>
4 bh 189 # Bernhard Herzog <[email protected]>
5 bh 6 #
6     # This program is free software under the GPL (>=v2)
7     # Read the file COPYING coming with Thuban for details.
8    
9     """
10     Thuban's application object.
11     """
12    
13     __version__ = "$Revision$"
14    
15 bh 189 import sys, os
16 frank 1133 import os.path
17    
18 bh 189 import traceback
19    
20 bh 6 from wxPython.wx import *
21    
22     from Thuban.Lib.connector import Publisher
23 frank 1150 from Thuban.Lib.fileutil import get_application_dir
24 bh 6
25 jan 374 from Thuban import _
26 bh 6 from Thuban.Model.session import create_empty_session
27     from Thuban.Model.save import save_session
28 bh 1650 from Thuban.Model.load import load_session, LoadCancelled
29 bh 242 from Thuban.Model.messages import MAPS_CHANGED
30 jonathan 1162 from Thuban.Model.layer import RasterLayer
31     import Thuban.Model.resource
32 bh 6
33     import view
34     import tree
35 bh 215 import mainwindow
36 bh 1654 import dbdialog
37 jan 1704 import exceptiondialog
38 bh 6
39 jonathan 503 from messages import SESSION_REPLACED
40 bh 6
41    
42     class ThubanApplication(wxApp, Publisher):
43    
44     """
45     Thuban's application class.
46    
47     All wxWindows programs have to have an instance of an application
48     class derived from wxApp. In Thuban the application class holds
49 bh 535 references to the main window and the session.
50 bh 6 """
51    
52     def OnInit(self):
53 jonathan 1518 sys.excepthook = self.ShowExceptionDialog
54 bh 2072
55     # Initialize instance variables before trying to create any
56     # windows. Creating windows can start an event loop if
57     # e.g. message boxes are popped up for some reason, and event
58     # handlers, especially EVT_UPDATE_UI may want to access things
59     # from the application.
60    
61     # Defaults for the directories used in file dialogs
62     self.path={"data":".", "projection":"."}
63    
64     self.session = None
65     self.top = None
66     self.create_session()
67    
68     # Create an optional splash screen and then the mainwindow
69 bh 401 self.splash = self.splash_screen()
70     if self.splash is not None:
71     self.splash.Show()
72 bh 189 self.read_startup_files()
73 bh 401 self.top = self.CreateMainWindow()
74     self.SetTopWindow(self.top)
75     if self.splash is None:
76     self.ShowMainWindow()
77 bh 2072
78 jonathan 518 return True
79 bh 6
80 bh 251 def OnExit(self):
81     """Clean up code.
82    
83     Extend this in derived classes if needed.
84     """
85     self.session.Destroy()
86 bh 765 self.session = None
87 bh 251 Publisher.Destroy(self)
88    
89 bh 189 def read_startup_files(self):
90     """Read the startup files."""
91     # for now the startup file is ~/.thuban/thubanstart.py
92 frank 1150 dir = get_application_dir()
93 bh 189 if os.path.isdir(dir):
94     sys.path.append(dir)
95     try:
96     import thubanstart
97     except ImportError:
98     tb = sys.exc_info()[2]
99     try:
100     if tb.tb_next is not None:
101     # The ImportError exception was raised from
102     # inside the thubanstart module.
103 jan 374 sys.stderr.write(_("Cannot import the thubanstart"
104 bh 671 " module\n"))
105 bh 189 traceback.print_exc(None, sys.stderr)
106     else:
107     # There's no thubanstart module.
108 jan 374 sys.stderr.write(_("No thubanstart module available\n"))
109 bh 189 finally:
110     # make sure we delete the traceback object,
111     # otherwise there's be circular references involving
112     # the current stack frame
113     del tb
114     except:
115 jan 374 sys.stderr.write(_("Cannot import the thubanstart module\n"))
116 bh 189 traceback.print_exc(None, sys.stderr)
117     else:
118     # There's no .thuban directory
119 jan 374 sys.stderr.write(_("No ~/.thuban directory\n"))
120 bh 189
121 bh 401 def splash_screen(self):
122     """Create and return a splash screen.
123    
124     This method is called by OnInit to determine whether the
125     application should have a splashscreen. If the application
126     should display a splash screen override this method in a derived
127     class and have it create and return the wxSplashScreen instance.
128     The implementation of this method in the derived class should
129     also arranged for ShowMainWindow to be called.
130    
131     The default implementation simply returns None so that no splash
132     screen is shown and ShowMainWindow will be called automatically.
133     """
134     return None
135    
136     def ShowMainWindow(self):
137     """Show the main window
138    
139     Normally this method is automatically called by OnInit to show
140     the main window. However, if the splash_screen method has
141     returned a splashscreen it is expected that the derived class
142     also arranges for ShowMainWindow to be called at the appropriate
143     time.
144     """
145 jonathan 518 self.top.Show(True)
146 bh 535
147 bh 235 def CreateMainWindow(self):
148     """Create and return the main window for the application.
149    
150     Override this in subclasses to instantiate the Thuban mainwindow
151     with different parameters or to use a different class for the
152     main window.
153     """
154 jan 374 msg = (_("This is the wxPython-based Graphical User Interface"
155     " for exploring geographic data"))
156 bh 535 return mainwindow.MainWindow(NULL, -1, "Thuban", self, None,
157 jonathan 934 initial_message = msg,
158     size = (600, 400))
159 bh 235
160 bh 219 def Session(self):
161     """Return the application's session object"""
162     return self.session
163    
164 bh 6 def SetSession(self, session):
165 bh 219 """Make session the new session.
166    
167 jonathan 503 Issue SESSION_REPLACED after self.session has become the new
168 bh 242 session. After the session has been assigned call
169     self.subscribe_session() with the new session and
170     self.unsubscribe_session with the old one.
171 bh 219 """
172 bh 6 oldsession = self.session
173     self.session = session
174 bh 242 self.subscribe_session(self.session)
175 jonathan 503 self.issue(SESSION_REPLACED)
176 bh 242 self.maps_changed()
177 bh 6 if oldsession is not None:
178 bh 242 self.unsubscribe_session(oldsession)
179 bh 6 oldsession.Destroy()
180    
181 frank 2051 def SetPath(self, group, filename):
182     """Store the application's default path for file dialogs extracted
183     from a given filename.
184     """
185     self.path[group] = os.path.dirname( filename )
186    
187     def Path(self, group):
188     """Return the application's default path for file dialogs."""
189     return self.path[group]
190    
191 bh 242 def subscribe_session(self, session):
192     """Subscribe to some of the sessions channels.
193    
194     Extend this method in derived classes if you need additional
195     channels.
196     """
197     session.Subscribe(MAPS_CHANGED, self.maps_changed)
198    
199     def unsubscribe_session(self, session):
200     """Unsubscribe from the sessions channels.
201    
202     Extend this method in derived classes if you subscribed to
203     additional channels in subscribe_session().
204     """
205     session.Unsubscribe(MAPS_CHANGED, self.maps_changed)
206    
207 bh 6 def create_session(self):
208 bh 242 """Create a default session.
209    
210     Override this method in derived classes to instantiate the
211     session differently or to use a different session class. Don't
212     subscribe to channels here yet. Do that in the
213     subscribe_session() method.
214     """
215 bh 6 self.SetSession(create_empty_session())
216    
217 bh 1648 def OpenSession(self, filename, db_connection_callback = None):
218 bh 592 """Open the session in the file named filename"""
219     # Make sure we deal with an absolute pathname. Otherwise we can
220     # get problems when saving because the saving code expects an
221     # absolute directory name
222     filename = os.path.abspath(filename)
223 bh 1654 if db_connection_callback is None:
224     db_connection_callback = self.run_db_param_dialog
225 bh 1650 try:
226     session = load_session(filename,
227     db_connection_callback=db_connection_callback)
228     except LoadCancelled:
229     return
230 bh 6 session.SetFilename(filename)
231     session.UnsetModified()
232     self.SetSession(session)
233    
234 jonathan 1162 for map in session.Maps():
235     for layer in map.Layers():
236     if isinstance(layer, RasterLayer) \
237     and not Thuban.Model.resource.has_gdal_support():
238 bh 1566 msg = _("The current session contains Image layers,\n"
239     "but the GDAL library is not available to "
240 jonathan 1162 "draw them.")
241 bh 1566 dlg = wx.wxMessageDialog(None,
242     msg,
243 jonathan 1162 _("Library not available"),
244     wx.wxOK | wx.wxICON_INFORMATION)
245     print msg
246     dlg.ShowModal()
247     dlg.Destroy()
248     break
249    
250 bh 1654 def run_db_param_dialog(self, parameters, message):
251     """Implementation of the db_connection_callback for loading sessions"""
252     dlg = dbdialog.DBDialog(None, _("DB Connection Parameters"),
253     parameters, message)
254     return dlg.RunDialog()
255    
256    
257 bh 6 def SaveSession(self):
258     save_session(self.session, self.session.filename)
259    
260 bh 242 def maps_changed(self, *args):
261 bh 1776 """Subscribed to the session's MAPS_CHANGED messages.
262    
263     Set the toplevel window's map to the map in the session. This is
264     done by calling the window's SetMap method with the map as
265     argument. If the session doesn't have any maps None is used
266     instead.
267    
268     Currently Thuban can only really handle at most one map in a
269     sessions so the first map in the session's list of maps as
270     returned by the Maps method is used.
271     """
272 bh 2072 # The mainwindow may not have been created yet, so check whether
273     # it has been created before calling any of its methods
274     if self.top is not None:
275     if self.session.HasMaps():
276     self.top.SetMap(self.session.Maps()[0])
277     else:
278     self.top.SetMap(None)
279 jonathan 1390
280 jonathan 1518 in_exception_dialog = 0 # flag: are we already inside the exception dialog?
281 jonathan 1390
282 jonathan 1518 def ShowExceptionDialog(self, exc_type, exc_value, exc_traceback):
283     """Show a message box with information about an exception.
284    
285     The parameters are the usual values describing an exception in
286     Python, the exception type, the value and the traceback.
287    
288     This method can be used as a value for the sys.excepthook.
289     """
290 jonathan 1390
291 jonathan 1518 if self.in_exception_dialog:
292     return
293     self.in_exception_dialog = 1
294     while wxIsBusy():
295     wxEndBusyCursor() # reset the mouse cursor
296 jonathan 1390
297 jonathan 1518 try:
298     lines = traceback.format_exception(exc_type, exc_value,
299     exc_traceback)
300 bh 1874 message = _("An unhandled exception occurred:\n%s\n"
301     "(please report to"
302     " http://thuban.intevation.org/bugtracker.html)"
303     "\n\n%s") % (exc_value, "".join(lines))
304 jonathan 1518 print message
305 jonathan 1390
306 jonathan 1518 # We don't use an explicit parent here because this method might
307     # be called in circumstances where the main window doesn't exist
308     # anymore.
309 jan 1704 exceptiondialog.run_exception_dialog(None, message)
310 jonathan 1390
311 jonathan 1518 finally:
312     self.in_exception_dialog = 0
313     # delete the last exception info that python keeps in
314     # sys.last_* because especially last_traceback keeps
315     # indirect references to all objects bound to local
316     # variables and this might prevent some object from being
317     # collected early enough.
318     sys.last_type = sys.last_value = sys.last_traceback = None
319 jonathan 1390

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26