/[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 851 - (hide annotations)
Wed May 7 15:11:12 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: 9846 byte(s)
* Thuban/Model/session.py (Session.__init__): New instance
variable shapestores to hold a list of all open shapestore objects
(Session.ShapeStores): New. Accessor method for the shapestores
list.
(Session._add_shapestore, Session._clean_weak_store_refs): New.
Internal methods to maintain the shapestores list.
(Session.Tables): New. Return all tables open in the session.
(Session.OpenShapefile): Insert the new ShapeStore into the
shapestores list.

* test/test_session.py (TestSessionSimple.test_initial_state): Add
tests for ShapeStores and Tables
(TestSessionWithContent.test_shape_stores)
(TestSessionWithContent.test_tables): New. Test cases for
ShapeStores and Tables

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 bh 851 self.shapestores = []
133 jan 197 self.extensions = []
134 bh 765 self.temp_dir = None
135     self.transient_db = None
136 bh 6
137 bh 232 def changed(self, channel = None, *args):
138     """Like the inherited version but issue a CHANGED message as well.
139    
140     The CHANGED message is only issued if channel given is a
141     different channel than CHANGED.
142     """
143     Modifiable.changed(self, channel, *args)
144     if channel != CHANGED:
145     self.issue(CHANGED, self)
146    
147 bh 6 def SetFilename(self, filename):
148     self.filename = filename
149     self.changed(FILENAME_CHANGED)
150    
151     def Maps(self):
152     return self.maps
153    
154     def HasMaps(self):
155     return len(self.maps) > 0
156    
157     def AddMap(self, map):
158     self.maps.append(map)
159 bh 128 for channel in self.forwarded_channels:
160 bh 6 map.Subscribe(channel, self.forward, channel)
161     self.changed(MAPS_CHANGED)
162    
163 bh 241 def RemoveMap(self, map):
164     for channel in self.forwarded_channels:
165     map.Unsubscribe(channel, self.forward, channel)
166     self.maps.remove(map)
167     self.changed(MAPS_CHANGED)
168     map.Destroy()
169    
170 jan 197 def Extensions(self):
171     return self.extensions
172    
173     def HasExtensions(self):
174     return len(self.extensions) > 0
175    
176     def AddExtension(self, extension):
177     self.extensions.append(extension)
178     for channel in self.forwarded_channels:
179     extension.Subscribe(channel, self.forward, channel)
180     self.changed(EXTENSIONS_CHANGED)
181    
182 bh 851 def ShapeStores(self):
183     """Return a list of all ShapeStore objects open in the session"""
184     return [store() for store in self.shapestores]
185    
186     def _add_shapestore(self, store):
187     """Internal: Add the shapestore to the list of shapestores"""
188     self.shapestores.append(weakref.ref(store,
189     self._clean_weak_store_refs))
190    
191     def _clean_weak_store_refs(self, weakref):
192     """Internal: Remove the weakref from the shapestores list"""
193     self.shapestores = [store for store in self.shapestores
194     if store is not weakref]
195    
196     def Tables(self):
197     """Return a list of all table objects open in the session"""
198     # Tables are only available from shapestores at the moment, so
199     # we just take them from there
200     return [store.Table() for store in self.ShapeStores()]
201    
202 bh 765 def temp_directory(self):
203     """
204     Return the name of the directory for session specific temporary files
205    
206     Create the directory if it doesn't exist yet.
207     """
208     if self.temp_dir is None:
209     temp_dir = mktemp()
210     os.mkdir(temp_dir, 0700)
211     self.temp_dir = temp_dir
212     self.temp_dir_remover = AutoRemoveDir(self.temp_dir)
213     return self.temp_dir
214    
215 bh 723 def OpenShapefile(self, filename):
216     """Return a shapefile store object for the data in the given file"""
217 bh 851 store = ShapefileStore(self, filename)
218     self._add_shapestore(store)
219     return store
220 bh 723
221 bh 765 def TransientDB(self):
222     if self.transient_db is None:
223     filename = os.path.join(self.temp_directory(), "transientdb")
224     self.transient_db = TransientDatabase(filename)
225     #print self.temp_dir_remover
226     auto_remover[self.transient_db] = AutoRemoveFile(filename,
227     self.temp_dir_remover)
228     return self.transient_db
229    
230 bh 6 def Destroy(self):
231     for map in self.maps:
232     map.Destroy()
233     self.maps = []
234     self.tables = []
235 bh 250 Modifiable.Destroy(self)
236 bh 6
237 bh 778 # Close the transient DB explicitly so that it removes any
238     # journal files from the temporary directory
239     if self.transient_db is not None:
240     self.transient_db.close()
241    
242 bh 6 def forward(self, *args):
243 bh 232 """Reissue events.
244    
245     If the channel the event is forwarded to is a changed-channel
246     that is not the CHANGED channel issue CHANGED as well. An
247     channel is considered to be a changed-channel if it's name ends
248     with 'CHANGED'.
249     """
250 bh 6 if len(args) > 1:
251     args = (args[-1],) + args[:-1]
252     apply(self.issue, args)
253 bh 232 channel = args[0]
254     # It's a bit of a kludge to rely on the channel name for this.
255     if channel.endswith("CHANGED") and channel != CHANGED:
256     self.issue(CHANGED, self)
257 bh 6
258     def WasModified(self):
259     """Return true if the session or one of the maps was modified"""
260     if self.modified:
261     return 1
262     else:
263     for map in self.maps:
264     if map.WasModified():
265     return 1
266     return 0
267    
268     def UnsetModified(self):
269     """Unset the modified flag of the session and the maps"""
270     Modifiable.UnsetModified(self)
271     for map in self.maps:
272     map.UnsetModified()
273    
274 bh 217 def TreeInfo(self):
275     items = []
276     if self.filename is None:
277 jan 374 items.append(_("Filename:"))
278 bh 217 else:
279 jan 374 items.append(_("Filename: %s") % self.filename)
280 bh 6
281 bh 217 if self.WasModified():
282 jan 374 items.append(_("Modified"))
283 bh 217 else:
284 jan 374 items.append(_("Unmodified"))
285 bh 6
286 bh 217 items.extend(self.maps)
287     items.extend(self.extensions)
288    
289 jan 374 return (_("Session: %s") % self.title, items)
290 bh 217
291    
292 bh 6 def create_empty_session():
293     """Return an empty session useful as a starting point"""
294 jan 103 import os
295 jan 374 session = Session(_('unnamed session'))
296 jan 103 session.SetFilename(None)
297 jan 374 session.AddMap(Map(_('unnamed map')))
298 bh 56 session.UnsetModified()
299 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