/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/session.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/Model/session.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 778 - (hide annotations)
Tue Apr 29 14:54:17 2003 UTC (21 years, 10 months ago) by bh
Original Path: trunk/thuban/Thuban/Model/session.py
File MIME type: text/x-python
File size: 8862 byte(s)
(Session.Destroy): Explicitly close the
transient DB if it exists to make sure it doesn't leave a journal
file in the temp directory.

1 bh 723 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4 jan 197 # Jan-Oliver Wagner <[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     __version__ = "$Revision$"
10    
11 bh 765 import os
12     from tempfile import mktemp
13     import weakref
14    
15 jan 197 from messages import MAPS_CHANGED, EXTENSIONS_CHANGED, FILENAME_CHANGED, \
16 jonathan 548 MAP_LAYERS_CHANGED, MAP_PROJECTION_CHANGED, \
17 jonathan 582 LAYER_CHANGED, LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED,\
18 bh 232 EXTENSION_CHANGED, EXTENSION_OBJECTS_CHANGED, CHANGED
19 bh 6
20 jan 374 from Thuban import _
21    
22 bh 6 from base import TitledObject, Modifiable
23     from map import Map
24 bh 723 from data import ShapefileStore
25 bh 6
26 bh 765 from transientdb import TransientDatabase
27 bh 6
28 bh 765 class AutoRemoveFile:
29    
30     """Remove a file once all references go away."""
31    
32     def __init__(self, filename, tempdir = None):
33     """Initialize the AutoRemoveFile
34    
35     Parameters:
36     filename -- The name of the file to remove in __del__
37     tempdir -- Another object simple stored as an instance variable.
38    
39     As the name suggests the tempdir parameter is intended for a
40     temporary directory the file might be located in. The intended
41     use is that it's an instance of AutoRemoveDir.
42     """
43     self.filename = filename
44     self.tempdir = tempdir
45    
46     def __del__(self, remove = os.remove):
47     remove(self.filename)
48    
49     class AutoRemoveDir:
50    
51     """Remove a directory once all references go away
52    
53     The intended use of this class together with AutoRemoveFile is for
54     temporary directories and files containd therein. An AutoRemoveDir
55     should be instantiated for the directory and passed as the tempdir
56     parameter to every AutoRemoveFile instance created for files in the
57     directory. An AutoRemoveFile shold be instantiated for every file
58     created in the directory so that the directory is automatically
59     removed once the last file is removed.
60     """
61    
62     def __init__(self, filename):
63     """Initialize the AutoRemoveDir
64    
65     The parameter is the name of the directory.
66     """
67     self.filename = filename
68    
69     def __del__(self, rmdir = os.rmdir):
70     rmdir(self.filename)
71    
72    
73     # WeakKey dictionary mapping objects like the transient_db to
74     # AutoRemoveDir or AutoRemoveFile instances to make sure that the
75     # temporary files and the directory are deleted but not before the
76     # objects that use them go away.
77     auto_remover = weakref.WeakKeyDictionary()
78    
79 bh 6 class Session(TitledObject, Modifiable):
80    
81     """A complete session.
82    
83 jan 197 A Session consists of arbitrary numbers of maps, tables and extensions
84 bh 6
85     Session objects send the following events:
86    
87     TITLE_CHANGED -- The title has changed. Parameters: the session.
88    
89     FILENAME_CHANGED -- The filename has changed. No parameters.
90    
91     MAPS_CHANGED -- Maps were added, removed.
92    
93 jan 197 EXTENSIONS_CHANGED -- Extensions were added, removed.
94    
95 jonathan 548 MAP_LAYERS_CHANGED -- Same as the map's event of the same name.
96 bh 6 It's simply resent from the session to make
97     subscriptions easier.
98 bh 232
99     CHANGED -- Generic changed event. Parameters: the session. The
100     event is always issued when any other changed event
101     is issused. This is useful for code that needs to be
102     notified whenever something in the session has
103     changed but it's too cumbersome or error-prone to
104     subscribe to all the individual events.
105 bh 6 """
106    
107 bh 128 # message channels that have to be forwarded from maps contained in
108     # the session.
109     forwarded_channels = (
110 bh 318 # generic channels
111     CHANGED,
112    
113 bh 128 # map specific channels
114     MAP_PROJECTION_CHANGED,
115 jonathan 548 MAP_LAYERS_CHANGED,
116 bh 128
117     # layer channels forwarded by the map
118     LAYER_PROJECTION_CHANGED,
119 jonathan 582 LAYER_CHANGED,
120 jan 197 LAYER_VISIBILITY_CHANGED,
121 bh 128
122 jan 197 # channels forwarded by an extension
123     EXTENSION_CHANGED,
124     EXTENSION_OBJECTS_CHANGED)
125    
126 bh 6 def __init__(self, title):
127     TitledObject.__init__(self, title)
128     Modifiable.__init__(self)
129     self.filename = None
130     self.maps = []
131     self.tables = []
132 jan 197 self.extensions = []
133 bh 765 self.temp_dir = None
134     self.transient_db = None
135 bh 6
136 bh 232 def changed(self, channel = None, *args):
137     """Like the inherited version but issue a CHANGED message as well.
138    
139     The CHANGED message is only issued if channel given is a
140     different channel than CHANGED.
141     """
142     Modifiable.changed(self, channel, *args)
143     if channel != CHANGED:
144     self.issue(CHANGED, self)
145    
146 bh 6 def SetFilename(self, filename):
147     self.filename = filename
148     self.changed(FILENAME_CHANGED)
149    
150     def Maps(self):
151     return self.maps
152    
153     def HasMaps(self):
154     return len(self.maps) > 0
155    
156     def AddMap(self, map):
157     self.maps.append(map)
158 bh 128 for channel in self.forwarded_channels:
159 bh 6 map.Subscribe(channel, self.forward, channel)
160     self.changed(MAPS_CHANGED)
161    
162 bh 241 def RemoveMap(self, map):
163     for channel in self.forwarded_channels:
164     map.Unsubscribe(channel, self.forward, channel)
165     self.maps.remove(map)
166     self.changed(MAPS_CHANGED)
167     map.Destroy()
168    
169 jan 197 def Extensions(self):
170     return self.extensions
171    
172     def HasExtensions(self):
173     return len(self.extensions) > 0
174    
175     def AddExtension(self, extension):
176     self.extensions.append(extension)
177     for channel in self.forwarded_channels:
178     extension.Subscribe(channel, self.forward, channel)
179     self.changed(EXTENSIONS_CHANGED)
180    
181 bh 765 def temp_directory(self):
182     """
183     Return the name of the directory for session specific temporary files
184    
185     Create the directory if it doesn't exist yet.
186     """
187     if self.temp_dir is None:
188     temp_dir = mktemp()
189     os.mkdir(temp_dir, 0700)
190     self.temp_dir = temp_dir
191     self.temp_dir_remover = AutoRemoveDir(self.temp_dir)
192     return self.temp_dir
193    
194 bh 723 def OpenShapefile(self, filename):
195     """Return a shapefile store object for the data in the given file"""
196     return ShapefileStore(self, filename)
197    
198 bh 765 def TransientDB(self):
199     if self.transient_db is None:
200     filename = os.path.join(self.temp_directory(), "transientdb")
201     self.transient_db = TransientDatabase(filename)
202     #print self.temp_dir_remover
203     auto_remover[self.transient_db] = AutoRemoveFile(filename,
204     self.temp_dir_remover)
205     return self.transient_db
206    
207 bh 6 def Destroy(self):
208     for map in self.maps:
209     map.Destroy()
210     self.maps = []
211     self.tables = []
212 bh 250 Modifiable.Destroy(self)
213 bh 6
214 bh 778 # Close the transient DB explicitly so that it removes any
215     # journal files from the temporary directory
216     if self.transient_db is not None:
217     self.transient_db.close()
218    
219 bh 6 def forward(self, *args):
220 bh 232 """Reissue events.
221    
222     If the channel the event is forwarded to is a changed-channel
223     that is not the CHANGED channel issue CHANGED as well. An
224     channel is considered to be a changed-channel if it's name ends
225     with 'CHANGED'.
226     """
227 bh 6 if len(args) > 1:
228     args = (args[-1],) + args[:-1]
229     apply(self.issue, args)
230 bh 232 channel = args[0]
231     # It's a bit of a kludge to rely on the channel name for this.
232     if channel.endswith("CHANGED") and channel != CHANGED:
233     self.issue(CHANGED, self)
234 bh 6
235     def WasModified(self):
236     """Return true if the session or one of the maps was modified"""
237     if self.modified:
238     return 1
239     else:
240     for map in self.maps:
241     if map.WasModified():
242     return 1
243     return 0
244    
245     def UnsetModified(self):
246     """Unset the modified flag of the session and the maps"""
247     Modifiable.UnsetModified(self)
248     for map in self.maps:
249     map.UnsetModified()
250    
251 bh 217 def TreeInfo(self):
252     items = []
253     if self.filename is None:
254 jan 374 items.append(_("Filename:"))
255 bh 217 else:
256 jan 374 items.append(_("Filename: %s") % self.filename)
257 bh 6
258 bh 217 if self.WasModified():
259 jan 374 items.append(_("Modified"))
260 bh 217 else:
261 jan 374 items.append(_("Unmodified"))
262 bh 6
263 bh 217 items.extend(self.maps)
264     items.extend(self.extensions)
265    
266 jan 374 return (_("Session: %s") % self.title, items)
267 bh 217
268    
269 bh 6 def create_empty_session():
270     """Return an empty session useful as a starting point"""
271 jan 103 import os
272 jan 374 session = Session(_('unnamed session'))
273 jan 103 session.SetFilename(None)
274 jan 374 session.AddMap(Map(_('unnamed map')))
275 bh 56 session.UnsetModified()
276 bh 6 return session

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26