/[schmitzm]/trunk/src/skrueger/geotools/StyledFeatureCollection.java
ViewVC logotype

Diff of /trunk/src/skrueger/geotools/StyledFeatureCollection.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/src/skrueger/geotools/StyledFeatureCollection.java revision 221 by alfonx, Tue Jul 14 14:40:52 2009 UTC branches/1.0-gt2-2.6/src/skrueger/geotools/StyledFeatureCollection.java revision 324 by alfonx, Wed Aug 26 15:17:02 2009 UTC
# Line 1  Line 1 
1  package skrueger.geotools;  /*******************************************************************************
2     * Copyright (c) 2009 Martin O. J. Schmitz.
3  import java.io.IOException;   *
4  import java.net.URL;   * This file is part of the SCHMITZM library - a collection of utility
5  import java.util.HashMap;   * classes based on Java 1.6, focusing (not only) on Java Swing
6  import java.util.Map;   * and the Geotools library.
7     *
8  import javax.swing.ImageIcon;   * The SCHMITZM project is hosted at:
9     * http://wald.intevation.org/projects/schmitzm/
10  import org.geotools.data.FeatureSource;   *
11  import org.geotools.data.collection.CollectionDataStore;   * This program is free software; you can redistribute it and/or
12  import org.geotools.feature.AttributeType;   * modify it under the terms of the GNU Lesser General Public License
13  import org.geotools.feature.FeatureCollection;   * as published by the Free Software Foundation; either version 3
14  import org.geotools.feature.FeatureType;   * of the License, or (at your option) any later version.
15  import org.geotools.styling.Style;   *
16     * This program is distributed in the hope that it will be useful,
17  import schmitzm.geotools.feature.FeatureUtil;   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  import skrueger.AttributeMetaData;   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  import skrueger.i8n.Translation;   * GNU General Public License for more details.
20     *
21  /**   * You should have received a copy of the GNU Lesser General Public License (license.txt)
22   * This class provides a simple implementation of {@link StyledMapInterface} for   * along with this program; if not, write to the Free Software
23   * {@link FeatureCollection}. The uncache functionality is not supported,   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24   * because this class bases on an existing {@link FeatureCollection} object in   * or try this link: http://www.gnu.org/licenses/lgpl.html
25   * memory.   *
26   *   * Contributors:
27   * @author <a href="mailto:[email protected]">Martin Schmitz</a>   *     Martin O. J. Schmitz - initial API and implementation
28   *         (University of Bonn/Germany)   *     Stefan A. Krüger - additional utility classes
29   * @version 1.0   ******************************************************************************/
30   */  package skrueger.geotools;
31  public class StyledFeatureCollection extends  
32                  AbstractStyledMap<FeatureCollection> implements  import java.io.IOException;
33                  StyledFeatureCollectionInterface {  import java.net.URL;
34    import java.util.HashMap;
35          /** Holds the meta data for displaying a legend. */  import java.util.Map;
36          protected Map<Integer, AttributeMetaData> attrMetaData = null;  
37    import javax.swing.ImageIcon;
38          /**  
39           * We be filled with a "virtual" {@link FeatureSource} on demand.  import org.geotools.data.FeatureSource;
40           */  import org.geotools.data.collection.CollectionDataStore;
41          private FeatureSource featureSource = null;  import org.geotools.feature.AttributeType;
42    import org.geotools.feature.FeatureCollection;
43          /**  import org.opengis.feature.simple.SimpleFeature;
44           * Creates a styled {@link FeatureCollection} with language-specific  import org.opengis.feature.simple.SimpleFeatureType;
45           * informations.  import org.geotools.styling.Style;
46           *  
47           * @param fc  import schmitzm.geotools.feature.FeatureUtil;
48           *            the {@link FeatureCollection}  import skrueger.AttributeMetaData;
49           * @param id  import skrueger.i8n.Translation;
50           *            a unique ID for the object  
51           * @param title  /**
52           *            a (language-specific) short description   * This class provides a simple implementation of {@link StyledLayerInterface} for
53           * @param desc   * {@link FeatureCollection}. The uncache functionality is not supported,
54           *            a (language-specific) long description   * because this class bases on an existing {@link FeatureCollection} object in
55           * @param keywords   * memory.
56           *            (language-specific) keywords for the geo objects   *
57           * @param style   * @author <a href="mailto:[email protected]">Martin Schmitz</a>
58           *            a display style (if {@code null}, a default style is created)   *         (University of Bonn/Germany)
59           * @param attrMetaData   * @version 1.0
60           *            meta data for displaying a legend   */
61           * @param icon  public class StyledFeatureCollection extends
62           *            an icon for the object (can be {@code null})                  AbstractStyledLayer<FeatureCollection<SimpleFeatureType, SimpleFeature> > implements
63           * @exception IllegalArgumentException                  StyledFeatureCollectionInterface {
64           *                if {@code null} is given as ID or geo object  
65           */          /** Holds the meta data for displaying a legend. */
66          public StyledFeatureCollection(FeatureCollection fc, String id,          protected Map<Integer, AttributeMetaData> attrMetaData = null;
67                          Translation title, Translation desc, Translation keywords,  
68                          Style style, Map<Integer, AttributeMetaData> attrMetaData,          /**
69                          ImageIcon icon) {           * We be filled with a "virtual" {@link FeatureSource} on demand.
70                  super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()           */
71                                  .getCoordinateSystem(), id, title, desc, keywords, style, icon);          private FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = null;
72                  setAttributeMetaData(attrMetaData);  
73          }          /**
74             * Creates a styled {@link FeatureCollection} with language-specific
75          /**           * informations.
76           * Creates a styled {@link FeatureCollection} with language-specific           *
77           * informations.           * @param fc
78           *           *            the {@link FeatureCollection}
79           * @param fc           * @param id
80           *            the {@link FeatureCollection}           *            a unique ID for the object
81           * @param id           * @param title
82           *            a unique ID for the object           *            a (language-specific) short description
83           * @param title           * @param desc
84           *            a (language-specific) short description           *            a (language-specific) long description
85           * @param desc           * @param keywords
86           *            a (language-specific) long description           *            (language-specific) keywords for the geo objects
87           * @param keywords           * @param style
88           *            (language-specific) keywords for the geo objects           *            a display style (if {@code null}, a default style is created)
89           * @param style           * @param attrMetaData
90           *            a display style with attribute meta data information           *            meta data for displaying a legend
91           * @param icon           * @param icon
92           *            an icon for the object (can be {@code null})           *            an icon for the object (can be {@code null})
93           * @exception IllegalArgumentException           * @exception IllegalArgumentException
94           *                if {@code null} is given as ID or geo object           *                if {@code null} is given as ID or geo object
95           */           */
96          public StyledFeatureCollection(FeatureCollection fc, String id,          public StyledFeatureCollection(FeatureCollection fc, String id,
97                          Translation title, Translation desc, Translation keywords,                          Translation title, Translation desc, Translation keywords,
98                          StyledMapStyle<Map<Integer, AttributeMetaData>> style,                          Style style, Map<Integer, AttributeMetaData> attrMetaData,
99                          ImageIcon icon) {                          ImageIcon icon) {
100                  super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()                  super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()
101                                  .getCoordinateSystem(), id, title, desc, keywords,                                  .getCoordinateSystem(), id, title, desc, keywords, style, icon);
102                                  style != null ? style.getGeoObjectStyle() : null, icon);                  setAttributeMetaData(attrMetaData);
103                  setAttributeMetaData(style != null ? style.getMetaData() : null);          }
104          }  
105            /**
106          /**           * Creates a styled {@link FeatureCollection} with language-specific
107           * Creates a styled {@link FeatureCollection} with a language-specific           * informations.
108           * title, no long description, no keywords, default attribute meta data and           *
109           * no icon.           * @param fc
110           *           *            the {@link FeatureCollection}
111           * @param fc           * @param id
112           *            the {@link FeatureCollection}           *            a unique ID for the object
113           * @param id           * @param title
114           *            a unique ID for the object           *            a (language-specific) short description
115           * @param title           * @param desc
116           *            a short description           *            a (language-specific) long description
117           * @param style           * @param keywords
118           *            a display style (if {@code null}, a default style is created)           *            (language-specific) keywords for the geo objects
119           * @exception IllegalArgumentException           * @param style
120           *                if {@code null} is given as ID or geo object           *            a display style with attribute meta data information
121           * @see #createDefaultAttributeMetaDataMap(FeatureCollection)           * @param icon
122           */           *            an icon for the object (can be {@code null})
123          public StyledFeatureCollection(FeatureCollection fc, String id,           * @exception IllegalArgumentException
124                          Translation title, Style style) {           *                if {@code null} is given as ID or geo object
125                  this(fc, id, title, null, null, style, null, null);           */
126          }          public StyledFeatureCollection(FeatureCollection fc, String id,
127                            Translation title, Translation desc, Translation keywords,
128          /**                          StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
129           * Creates a styled {@link FeatureCollection} with non-translated                          ImageIcon icon) {
130           * informations.                  super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()
131           *                                  .getCoordinateSystem(), id, title, desc, keywords,
132           * @param fc                                  style != null ? style.getGeoObjectStyle() : null, icon);
133           *            the {@link FeatureCollection}                  setAttributeMetaData(style != null ? style.getMetaData() : null);
134           * @param id          }
135           *            a unique ID for the object  
136           * @param title          /**
137           *            a short description           * Creates a styled {@link FeatureCollection} with a language-specific
138           * @param desc           * title, no long description, no keywords, default attribute meta data and
139           *            a long description           * no icon.
140           * @param keywords           *
141           *            keywords for the geo objects           * @param fc
142           * @param style           *            the {@link FeatureCollection}
143           *            a display style (if {@code null}, a default style is created)           * @param id
144           * @param attrMetaData           *            a unique ID for the object
145           *            meta data for displaying a legend           * @param title
146           * @param icon           *            a short description
147           *            an icon for the object (can be {@code null})           * @param style
148           * @exception IllegalArgumentException           *            a display style (if {@code null}, a default style is created)
149           *                if {@code null} is given as ID or geo object           * @exception IllegalArgumentException
150           */           *                if {@code null} is given as ID or geo object
151          public StyledFeatureCollection(FeatureCollection fc, String id,           * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
152                          String title, String desc, String keywords, Style style,           */
153                          Map<Integer, AttributeMetaData> attrMetaData, ImageIcon icon) {          public StyledFeatureCollection(FeatureCollection fc, String id,
154                  this(fc, id, (Translation) null, null, null, style, attrMetaData, icon);                          Translation title, Style style) {
155                  setTitle(title);                  this(fc, id, title, null, null, style, null, null);
156                  setDesc(desc);          }
157                  setKeywords(keywords);  
158          }          /**
159             * Creates a styled {@link FeatureCollection} with non-translated
160          /**           * informations.
161           * Creates a styled {@link FeatureCollection} with non-translated           *
162           * informations.           * @param fc
163           *           *            the {@link FeatureCollection}
164           * @param fc           * @param id
165           *            the {@link FeatureCollection}           *            a unique ID for the object
166           * @param id           * @param title
167           *            a unique ID for the object           *            a short description
168           * @param title           * @param desc
169           *            a short description           *            a long description
170           * @param desc           * @param keywords
171           *            a long description           *            keywords for the geo objects
172           * @param keywords           * @param style
173           *            keywords for the geo objects           *            a display style (if {@code null}, a default style is created)
174           * @param style           * @param attrMetaData
175           *            a display style with attribute meta data information           *            meta data for displaying a legend
176           * @param icon           * @param icon
177           *            an icon for the object (can be {@code null})           *            an icon for the object (can be {@code null})
178           * @exception IllegalArgumentException           * @exception IllegalArgumentException
179           *                if {@code null} is given as ID or geo object           *                if {@code null} is given as ID or geo object
180           */           */
181          public StyledFeatureCollection(FeatureCollection fc, String id,          public StyledFeatureCollection(FeatureCollection fc, String id,
182                          String title, String desc, String keywords,                          String title, String desc, String keywords, Style style,
183                          StyledMapStyle<Map<Integer, AttributeMetaData>> style,                          Map<Integer, AttributeMetaData> attrMetaData, ImageIcon icon) {
184                          ImageIcon icon) {                  this(fc, id, (Translation) null, null, null, style, attrMetaData, icon);
185                  this(fc, id, title, desc, keywords, style != null ? style                  setTitle(title);
186                                  .getGeoObjectStyle() : null, style != null ? style                  setDesc(desc);
187                                  .getMetaData() : null, icon);                  setKeywords(keywords);
188          }          }
189    
190          /**          /**
191           * Creates a styled {@link FeatureCollection} with a non-translated title,           * Creates a styled {@link FeatureCollection} with non-translated
192           * no long description, no keywords, default attribute meta data and no           * informations.
193           * icon.           *
194           *           * @param fc
195           * @param fc           *            the {@link FeatureCollection}
196           *            the {@link FeatureCollection}           * @param id
197           * @param id           *            a unique ID for the object
198           *            a unique ID for the object           * @param title
199           * @param title           *            a short description
200           *            a short description           * @param desc
201           * @param style           *            a long description
202           *            a display style (if {@code null}, a default style is created)           * @param keywords
203           * @exception IllegalArgumentException           *            keywords for the geo objects
204           *                if {@code null} is given as ID or geo object           * @param style
205           * @see #createDefaultAttributeMetaDataMap(FeatureCollection)           *            a display style with attribute meta data information
206           */           * @param icon
207          public StyledFeatureCollection(FeatureCollection fc, String id,           *            an icon for the object (can be {@code null})
208                          String title, Style style) {           * @exception IllegalArgumentException
209                  this(fc, id, title, null, null, style, null, null);           *                if {@code null} is given as ID or geo object
210          }           */
211            public StyledFeatureCollection(FeatureCollection fc, String id,
212          /**                          String title, String desc, String keywords,
213           * Creates a styled {@link FeatureCollection} with a non-translated title,                          StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
214           * no long description, no keywords, default attribute meta data and no                          ImageIcon icon) {
215           * icon.                  this(fc, id, title, desc, keywords, style != null ? style
216           *                                  .getGeoObjectStyle() : null, style != null ? style
217           * @param fc                                  .getMetaData() : null, icon);
218           *            the {@link FeatureCollection}          }
219           * @param id  
220           *            a unique ID for the object          /**
221           * @param title           * Creates a styled {@link FeatureCollection} with a non-translated title,
222           *            a short description           * no long description, no keywords, default attribute meta data and no
223           * @param style           * icon.
224           *            a display style (if {@code null}, a default style is created)           *
225           * @exception IllegalArgumentException           * @param fc
226           *                if {@code null} is given as ID or geo object           *            the {@link FeatureCollection}
227           * @see #createDefaultAttributeMetaDataMap(FeatureCollection)           * @param id
228           */           *            a unique ID for the object
229          public StyledFeatureCollection(FeatureCollection fc, String id,           * @param title
230                          String title, StyledMapStyle<Map<Integer, AttributeMetaData>> style) {           *            a short description
231                  this(fc, id, title, null, null, style != null ? style           * @param style
232                                  .getGeoObjectStyle() : null, style != null ? style           *            a display style (if {@code null}, a default style is created)
233                                  .getMetaData() : null, null);           * @exception IllegalArgumentException
234          }           *                if {@code null} is given as ID or geo object
235             * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
236          /**           */
237           * Creates a default style for the {@link FeatureCollection}.          public StyledFeatureCollection(FeatureCollection fc, String id,
238           *                          String title, Style style) {
239           * @see FeatureUtil#createDefaultStyle(FeatureCollection)                  this(fc, id, title, null, null, style, null, null);
240           */          }
241          protected Style createDefaultStyle() {  
242                  return FeatureUtil.createDefaultStyle(geoObject);          /**
243          }           * Creates a styled {@link FeatureCollection} with a non-translated title,
244             * no long description, no keywords, default attribute meta data and no
245          /**           * icon.
246           * Returns the meta data needed for displaying a legend.           *
247           */           * @param fc
248          public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {           *            the {@link FeatureCollection}
249                  return attrMetaData;           * @param id
250          }           *            a unique ID for the object
251             * @param title
252          /**           *            a short description
253           * Sets the meta data needed for displaying a legend. If {@code legendData}           * @param style
254           * is {@code null} an empty map is set, so           *            a display style (if {@code null}, a default style is created)
255           * {@link #getAttributeMetaDataMap()} never returns {@code null}.           * @exception IllegalArgumentException
256           *           *                if {@code null} is given as ID or geo object
257           * @param attrMetaData           * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
258           *            map of attribute meta data           */
259           */          public StyledFeatureCollection(FeatureCollection fc, String id,
260          public void setAttributeMetaData(                          String title, StyledLayerStyle<Map<Integer, AttributeMetaData>> style) {
261                          Map<Integer, AttributeMetaData> attrMetaData) {                  this(fc, id, title, null, null, style != null ? style
262                  this.attrMetaData = (attrMetaData != null) ? attrMetaData                                  .getGeoObjectStyle() : null, style != null ? style
263                                  : createDefaultAttributeMetaDataMap(geoObject);                                  .getMetaData() : null, null);
264          }          }
265    
266          /**          /**
267           * Creates non-translated default meta data for a {@link FeatureCollection}           * Creates a default style for the {@link FeatureCollection}.
268           * with all attributes visible and no unit set.           *
269           *           * @see FeatureUtil#createDefaultStyle(FeatureCollection)
270           * @param fc           */
271           *            a {@link FeatureCollection}          protected Style createDefaultStyle() {
272           */                  return FeatureUtil.createDefaultStyle(geoObject);
273          public static Map<Integer, AttributeMetaData> createDefaultAttributeMetaDataMap(          }
274                          FeatureCollection fc) {  
275                  HashMap<Integer, AttributeMetaData> metaDataMap = new HashMap<Integer, AttributeMetaData>();          /**
276                  FeatureType ftype = fc.getSchema();           * Returns the meta data needed for displaying a legend.
277                  for (int i = 0; i < ftype.getAttributeCount(); i++) {           */
278                          AttributeType aType = ftype.getAttributeType(i);          public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {
279                          if (aType != ftype.getDefaultGeometry())                  return attrMetaData;
280                                  metaDataMap.put(i, new AttributeMetaData(i, // Column no.          }
281                                                  true, // visible  
282                                                  new Translation(aType.getName()), // Column name          /**
283                                                  new Translation(), // description           * Sets the meta data needed for displaying a legend. If {@code legendData}
284                                                  "" // Unit           * is {@code null} an empty map is set, so
285                                  ));           * {@link #getAttributeMetaDataMap()} never returns {@code null}.
286                  }           *
287                  return metaDataMap;           * @param attrMetaData
288          }           *            map of attribute meta data
289             */
290          /**          public void setAttributeMetaData(
291           * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and                          Map<Integer, AttributeMetaData> attrMetaData) {
292           * {@link #attrMetaData} to {@code null}.                  this.attrMetaData = (attrMetaData != null) ? attrMetaData
293           */                                  : createDefaultAttributeMetaDataMap(geoObject);
294          public void dispose() {          }
295                  this.geoObject = null;  
296                  this.envelope = null;          /**
297                  this.crs = null;           * Creates non-translated default meta data for a {@link FeatureCollection}
298                  this.attrMetaData = null;           * with all attributes visible and no unit set.
299          }           *
300             * @param fc
301          /**           *            a {@link FeatureCollection}
302           * Tests whether the geo object is disposed.           */
303           */          public static Map<Integer, AttributeMetaData> createDefaultAttributeMetaDataMap(
304          public boolean isDisposed() {                          FeatureCollection fc) {
305                  return geoObject == null;                  HashMap<Integer, AttributeMetaData> metaDataMap = new HashMap<Integer, AttributeMetaData>();
306          }                  SimpleFeatureType ftype = fc.getSchema();
307                    for (int i = 0; i < ftype.getAttributeCount(); i++) {
308          /**                          AttributeType aType = ftype.getAttributeType(i);
309           * Does nothing, because the {@link AbstractStyledMap} bases on existing                          if (aType != ftype.getDefaultGeometry())
310           * objects (in memory) which can not be uncached and reloaded.                                  metaDataMap.put(i, new AttributeMetaData(i, // Column no.
311           */                                                  true, // visible
312          public void uncache() {                                                  new Translation(aType.getName()), // Column name
313                                                    new Translation(), // description
314                  /** It will be recreated on the next getFetureSource() **/                                                  "" // Unit
315                  featureSource = null;                                  ));
316                    }
317                  LOGGER                  return metaDataMap;
318                                  .warn("Uncache onyl uncached any virtual FeatureSource. Object remains in memory.");          }
319          }  
320            /**
321          /*           * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and
322           * (non-Javadoc)           * {@link #attrMetaData} to {@code null}.
323           *           */
324           * @see skrueger.geotools.StyledMapInterface#getInfoURL()          public void dispose() {
325           */                  this.geoObject = null;
326          public URL getInfoURL() {                  this.envelope = null;
327                  return null;                  this.crs = null;
328          }                  this.attrMetaData = null;
329            }
330          /**  
331           * Same as {@link #getGeoObject()} method, but complies to the {@link StyledFeatureInterface}          /**
332           * @see {@link StyledFeatureInterface}           * Tests whether the geo object is disposed.
333           */           */
334          @Override          public boolean isDisposed() {
335          public FeatureCollection getFeatureCollection() {                  return geoObject == null;
336                  return getGeoObject();          }
337          }  
338            /**
339          /**           * Does nothing, because the {@link AbstractStyledLayer} bases on existing
340           * Returns a virtual {@link FeatureSource} to access the           * objects (in memory) which can not be uncached and reloaded.
341           * {@link FeatureCollection}. Once created, it will be reused until           */
342           * {@link #uncache()} is called.<br/>          public void uncache() {
343           * @see {@link StyledFeatureInterface}  
344           */                  /** It will be recreated on the next getFetureSource() **/
345          @Override                  featureSource = null;
346          public FeatureSource getFeatureSource() {  
347                  if (featureSource == null) {                  LOGGER
348                          CollectionDataStore store = new CollectionDataStore(getGeoObject());                                  .warn("Uncache onyl uncached any virtual FeatureSource. Object remains in memory.");
349                          try {          }
350                                  featureSource = store.getFeatureSource(store.getTypeNames()[0]);  
351                          } catch (IOException e) {          /*
352                                  throw new RuntimeException(           * (non-Javadoc)
353                                                  "Could not create a FeatureSource from the CollectionDataStore:",           *
354                                                  e);           * @see skrueger.geotools.StyledLayerInterface#getInfoURL()
355                          }           */
356                  }          public URL getInfoURL() {
357                  return featureSource;                  return null;
358          }          }
359    
360  }          /**
361             * Same as {@link #getGeoObject()} method, but complies to the {@link StyledFeaturesInterface}
362             * @see {@link StyledFeaturesInterface}
363             */
364            @Override
365            public FeatureCollection getFeatureCollection() {
366                    return getGeoObject();
367            }
368    
369            /**
370             * Returns a virtual {@link FeatureSource} to access the
371             * {@link FeatureCollection}. Once created, it will be reused until
372             * {@link #uncache()} is called.<br/>
373             * @see {@link StyledFeaturesInterface}
374             */
375            @Override
376            public FeatureSource getFeatureSource() {
377                    if (featureSource == null) {
378                            CollectionDataStore store = new CollectionDataStore(getGeoObject());
379                            try {
380                                    featureSource = store.getFeatureSource(store.getTypeNames()[0]);
381                            } catch (IOException e) {
382                                    throw new RuntimeException(
383                                                    "Could not create a FeatureSource from the CollectionDataStore:",
384                                                    e);
385                            }
386                    }
387                    return featureSource;
388            }
389    
390    }

Legend:
Removed from v.221  
changed lines
  Added in v.324

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26