001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.tax;
042:
043: import java.util.Map;
044: import java.util.Set;
045: import java.util.List;
046: import java.util.LinkedList;
047: import java.util.Collection;
048: import java.util.HashMap;
049: import java.util.Iterator;
050:
051: //import java.beans.PropertyChangeListener;
052: //import java.beans.PropertyChangeEvent;
053:
054: /**
055: *
056: * @author Libor Kramolis
057: * @version 0.1
058: */
059: public class TreeNamedObjectMap extends TreeObjectList {
060:
061: /** */
062: private Map map; // index to underlaying list -- lazy initialized by getMap()
063:
064: /** */
065: private KeyListener keyListener; // lazy initialized by getKeyListener()
066:
067: //
068: // init
069: //
070:
071: /**
072: * Creates new TreeNamedObjectMap.
073: */
074: protected TreeNamedObjectMap(ContentManager contentManager) {
075: super (contentManager);
076:
077: this .map = null;
078: this .keyListener = null;
079: }
080:
081: /** Creates new TreeNamedObjectMap -- copy constructor. */
082: protected TreeNamedObjectMap(TreeNamedObjectMap namedObjectMap) {
083: super (namedObjectMap);
084: }
085:
086: //
087: // itself
088: //
089:
090: /**
091: */
092: private KeyListener getKeyListener() {
093: if (this .keyListener == null) {
094: this .keyListener = new KeyListener();
095: }
096: return keyListener;
097: }
098:
099: //
100: // Map
101: //
102:
103: /**
104: */
105: private Map getMap() {
106: if (this .map == null) {
107: this .map = new HashMap(3);
108: }
109: return map;
110: }
111:
112: /**
113: */
114: private void mapClear() {
115: Iterator it = getMap().values().iterator();
116: while (it.hasNext()) {
117: NamedObject namedObject = (NamedObject) it.next();
118: namedObject.setKeyListener(null);
119: // namedObject.removePropertyChangeListener (namedObject.mapKeyPropertyName(), getKeyListener());
120: }
121: getMap().clear();
122: }
123:
124: /**
125: */
126: private Object mapPut(NamedObject namedObject) {
127: Object obj = getMap().put(namedObject.mapKey(), namedObject);
128: namedObject.setKeyListener(getKeyListener());
129: // namedObject.addPropertyChangeListener (namedObject.mapKeyPropertyName(), getKeyListener());
130:
131: return obj;
132: }
133:
134: /**
135: */
136: private Object mapRemove(NamedObject namedObject) {
137: Object obj = getMap().remove(namedObject.mapKey());
138: namedObject.setKeyListener(null);
139: // namedObject.removePropertyChangeListener (namedObject.mapKeyPropertyName(), getKeyListener());
140:
141: return obj;
142: }
143:
144: //
145: // from TreeObject
146: //
147:
148: /**
149: */
150: public Object clone() {
151: return new TreeNamedObjectMap(this );
152: }
153:
154: /**
155: */
156: public boolean equals(Object object, boolean deep) {
157: if (!!!super .equals(object, deep))
158: return false;
159:
160: TreeNamedObjectMap peer = (TreeNamedObjectMap) object;
161:
162: if (this .getMap().size() != peer.getMap().size())
163: return false;
164:
165: Iterator this It = this .getMap().keySet().iterator();
166: Iterator peerIt = peer.getMap().keySet().iterator();
167: while (this It.hasNext()) {
168: Object this Next = this It.next();
169: Object peerNext = peerIt.next();
170: if (!!!Util.equals(this Next, peerNext))
171: return false;
172: if (!!!Util.equals(this .getMap().get(this Next), peer
173: .getMap().get(peerNext)))
174: return false;
175: }
176:
177: return true;
178: }
179:
180: /*
181: * Update index to underlaying list.
182: * @see #findMergeCandidate
183: */
184: public void merge(TreeObject treeObject)
185: throws CannotMergeException {
186: mapClear();
187:
188: super .merge(treeObject);
189: }
190:
191: /*
192: * Suitable is a member with equalent mapKey.
193: */
194: protected int findMergeCandidate(final TreeObject original,
195: final TreeObject[] candidates) {
196: if ((original instanceof NamedObject) == false)
197: return -1;
198:
199: for (int i = 0; i < candidates.length; i++) {
200: TreeObject candidate = candidates[i];
201: if (candidate == null)
202: continue;
203: if (candidate instanceof NamedObject) {
204: Object key1 = ((NamedObject) candidate).mapKey();
205: Object key2 = ((NamedObject) original).mapKey();
206:
207: if (key2 != null && key2.equals(key1))
208: return i;
209: }
210: }
211:
212: return -1;
213: }
214:
215: //
216: // itself
217: //
218:
219: /**
220: */
221: public final Object get(Object mapKey) {
222: return getMap().get(mapKey);
223: }
224:
225: //
226: // from TreeObjectList
227: //
228:
229: /**
230: */
231: protected boolean removeImpl(Object obj) throws ClassCastException {
232: boolean removed = super .removeImpl(obj);
233:
234: if (removed) {
235: mapRemove((NamedObject) obj);
236: }
237:
238: return removed;
239: }
240:
241: /**
242: */
243: protected Object setImpl(int index, Object obj)
244: throws ClassCastException {
245: Object oldObj = super .setImpl(index, obj);
246:
247: mapRemove((NamedObject) oldObj);
248: mapPut((NamedObject) obj);
249:
250: return oldObj;
251: }
252:
253: /**
254: */
255: protected Object removeImpl(int index) {
256: Object oldObj = super .removeImpl(index);
257:
258: if (Util.THIS.isLoggable()) /* then */
259: Util.THIS.debug("\nTreeNamedObjectMap::removeImpl [ "
260: + index + " ] = " + oldObj); // NOI18N
261:
262: if (oldObj != null) {
263: mapRemove((NamedObject) oldObj);
264: }
265:
266: return (oldObj);
267: }
268:
269: /**
270: */
271: protected void addImpl(int index, Object obj)
272: throws ClassCastException {
273: Object oldObj = getMap().get(((NamedObject) obj).mapKey());
274:
275: if (oldObj != null) {
276: remove(oldObj);
277: }
278:
279: super .addImpl(index, obj);
280:
281: mapPut((NamedObject) obj);
282: }
283:
284: /**
285: */
286: protected boolean addImpl(Object obj) throws ClassCastException {
287: Object oldObj = getMap().get(((NamedObject) obj).mapKey());
288:
289: if (oldObj != null) {
290: remove(oldObj);
291: }
292:
293: boolean added = super .addImpl(obj);
294:
295: if (added) {
296: mapPut((NamedObject) obj);
297: }
298:
299: return added;
300: }
301:
302: //
303: // util
304: //
305:
306: /**
307: */
308: /* private void keyChanged (Object oldKey, Object newKey) {
309: Object oldValue = getMap().remove (oldKey);
310: Object newValue = getMap().get (newKey);
311:
312: if ( newValue != null ) {
313: remove (newValue);
314: }
315:
316: getMap().put (newKey, oldValue);
317: }*/
318:
319: /**
320: */
321: private void keyChanged(Object oldKey) {
322: Object oldValue = getMap().remove(oldKey);
323: Object newKey = ((NamedObject) oldValue).mapKey();
324: Object newValue = getMap().get(newKey);
325:
326: if (newValue != null) {
327: remove(newValue);
328: }
329:
330: getMap().put(newKey, oldValue);
331: }
332:
333: //
334: // class NamedObject
335: //
336:
337: /**
338: * Gives possibility to TreeNamedObjectMap to create a key for the object.
339: */
340: public static interface NamedObject {
341:
342: /** Used as key in map.
343: */
344: public Object mapKey();
345:
346: /** Attach NamedObject to NamedObject Map. */
347: public void setKeyListener(KeyListener keyListener);
348:
349: /** Used to listen on key value change.
350: */
351: // public String mapKeyPropertyName ();
352: /**
353: */
354: // public void addPropertyChangeListener (String propertyName,
355: // PropertyChangeListener listener);
356: /**
357: */
358: // public void removePropertyChangeListener (String propertyName,
359: // PropertyChangeListener listener);
360: } // end: interface NamedObject
361:
362: //
363: // class ContentManager
364: //
365:
366: /**
367: *
368: */
369: protected static abstract class ContentManager extends
370: TreeObjectList.ContentManager {
371:
372: /** @throws ClassCastException
373: */
374: public void checkAssignableObject(Object obj)
375: throws ClassCastException {
376: super .checkAssignableObject(obj);
377: if (!!!(obj instanceof NamedObject)) {
378: String msg = Util.THIS
379: .getString("EXC_instance_of_NamedObject"); //,obj.getClass().getName());
380: throw new ClassCastException(msg);
381: }
382: }
383:
384: } // end: interface ContentManager
385:
386: //
387: // class KeyListener
388: //
389:
390: /**
391: *
392: */
393: public class KeyListener {
394:
395: private KeyListener() {
396: }
397:
398: /** Map Key changed. */
399: public void mapKeyChanged(Object oldKey) {
400: TreeNamedObjectMap.this .keyChanged(oldKey);
401: }
402:
403: /** */
404: // public void propertyChange (PropertyChangeEvent pche) {
405: // TreeNamedObjectMap.this.keyChanged (pche.getOldValue(), pche.getNewValue());
406: // }
407: } // end: class KeyListener
408:
409: }
|