001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.event;
017:
018: import java.util.HashSet;
019: import java.util.Iterator;
020: import java.util.logging.Level;
021: import java.util.logging.Logger;
022:
023: /**
024: * Provides basic StyleEvent notification, may be used in conjuction with
025: * StyleList during event handling.
026: *
027: * <p>
028: * This class has package scope to prevent user code mistaking it for something
029: * important. It is only used to assist in the construction of this one
030: * implementation of StyleEvents. Basically this is NOT API :-)
031: * </p>
032: *
033: * @since 2.2.M3
034: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/event/AbstractGTRoot.java $
035: */
036: public abstract class AbstractGTRoot extends AbstractGTComponent
037: implements GTRoot {
038: /** The logger for the default core module. */
039: private static final Logger LOGGER = org.geotools.util.logging.Logging
040: .getLogger("org.geotools.event");
041:
042: // GTComponent notificationParent = GTRoot.NO_PARENT;
043: // protected String notificationName = "";
044: // protected int notificationPosition = GTDelta.NO_INDEX;
045: GTNote notification = new GTNoteImpl(GTRoot.NO_PARENT, "",
046: GTDelta.NO_INDEX);
047: private HashSet listeners;
048:
049: protected Object clone() throws CloneNotSupportedException {
050: AbstractGTRoot copy = (AbstractGTRoot) super .clone();
051:
052: // copy.notificationParent = GTRoot.NO_PARENT;
053: // copy.notificationName = "";
054: // copy.notificationPosition = GTDelta.NO_INDEX;
055: copy.notification = new GTNoteImpl(GTRoot.NO_PARENT, "",
056: GTDelta.NO_INDEX);
057:
058: return copy;
059: }
060:
061: /**
062: * Provide notification based on the provided delta.
063: *
064: * <p>
065: * Delta must come from this StyleComponent.
066: * </p>
067: *
068: * @param childDelta object containing change information protected void
069: * fire(GTDelta delta){ parent.changed(delta); }
070: */
071: /**
072: * Used to pass on "something is about to change" notification from
073: * children.
074: *
075: * @param childDelta object containing change information
076: */
077: public void removed(GTDelta childDelta) {
078: GTDelta delta = new GTDeltaImpl(notification,
079: GTDelta.Kind.NO_CHANGE, this , null, childDelta);
080: notification.getParent().removed(delta);
081: }
082:
083: /**
084: * Used to pass on "We changed" notification from children.
085: *
086: * @param childDelta object containing change information
087: */
088: public void changed(GTDelta childDelta) {
089: GTDelta delta = new GTDeltaImpl(notification,
090: GTDelta.Kind.NO_CHANGE, this , null, childDelta);
091: notification.getParent().removed(delta);
092: }
093:
094: /**
095: * Simple notification that we changed.
096: *
097: * <p>
098: * Change will be passed on to parent.changed( delta ).
099: * </p>
100: */
101: protected void fireChanged() {
102: GTDelta delta = new GTDeltaImpl(notification,
103: GTDelta.Kind.CHANGED, this , null);
104: notification.getParent().changed(delta);
105: }
106:
107: /**
108: * Create a child delta and send it off.
109: *
110: * <p>
111: * Use this for changes to simple types like int and Color.
112: * </p>
113: *
114: * @param childName used to the child (often bean propertyName or map key)
115: * @param child
116: * @param oldValue DOCUMENT ME!
117: */
118: final protected void fireChildChanged(String childName,
119: Object child, Object oldValue) {
120: if (child == null) {
121: fireChanged(); // well something changed
122: } else {
123: GTDelta delta;
124: delta = new GTDeltaImpl(new GTNoteImpl(childName,
125: GTDelta.NO_INDEX), GTDelta.Kind.CHANGED, child);
126: delta = new GTDeltaImpl(notification,
127: GTDelta.Kind.NO_CHANGE, this );
128: notification.getParent().changed(delta);
129: }
130: }
131:
132: // public GTComponent getParent() {
133: // return notification.getParent();
134: // }
135: // public void setParent(GTComponent newParent) {
136: // notification.setParent(newParent);
137: // }
138: // public void setNotificationName(String name) {
139: // if( name == null ) name = "";
140: // notificationName = name;
141: // }
142: //
143: // public String getNotificationName() {
144: // return notificationName;
145: // }
146: //
147: // public void setNotificationPosition(int index) {
148: // notificationPosition = index;
149: // }
150: //
151: // public int getNotificationPosition() {
152: // return notificationPosition;
153: // }
154:
155: /**
156: * Listens to changes in the Style content.
157: *
158: * <p>
159: * Changes are provided:
160: *
161: * <ul>
162: * <li>
163: * Before: deletion
164: * </li>
165: * <li>
166: * After: modification
167: * </li>
168: * </ul>
169: * </p>
170: *
171: * <p>
172: * Since the Style data structure can be vast and complicated a trail of
173: * breadcrumbs (a delta) is provided to help find your way to the change.
174: * </p>
175: *
176: * @param listener
177: */
178: public synchronized void addListener(GTListener listener) {
179: if (listeners == null) {
180: listeners = new HashSet();
181: }
182:
183: listeners.add(listener);
184: }
185:
186: /**
187: * Remove a style listener
188: *
189: * @param listener Listen to notifications
190: */
191: public synchronized void removeListener(GTListener listener) {
192: listeners.remove(listener);
193: }
194:
195: /**
196: * Provides notification of daring do (and undo) in style space.
197: *
198: * @param event Event describing notification
199: */
200: protected synchronized void fire(GTEvent event) {
201: assert event != null;
202:
203: for (Iterator i = listeners.iterator(); i.hasNext();) {
204: GTListener listener = (GTListener) i.next();
205:
206: try {
207: listener.changed(event);
208: } catch (Throwable t) {
209: //LOGGER.log( Level.SEVERE, listener.getClass().getSimpleName() + " encountered a serious problem", t );
210: LOGGER.log(Level.SEVERE,
211: "GTListener encountered a serious problem", t);
212: }
213: }
214: }
215:
216: /**
217: * Issue a change event w/ POST_CHANGE
218: *
219: * @param delta Used to quickly fire off a child delta
220: */
221: protected synchronized void fire(GTDelta delta) {
222: if (!hasListeners()) {
223: return;
224: }
225:
226: GTEventImpl event = new GTEventImpl(this ,
227: GTEvent.Type.POST_CHANGE, delta);
228: fire(event);
229: }
230:
231: protected boolean hasListeners() {
232: return (listeners != null) && !listeners.isEmpty();
233: }
234: }
|