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:
042: package org.netbeans.modules.dbschema.nodes;
043:
044: import java.beans.PropertyChangeListener;
045: import java.beans.PropertyChangeEvent;
046: import java.util.*;
047:
048: import org.openide.nodes.Children;
049: import org.openide.nodes.Node; //import org.openide.cookies.FilterCookie;
050: import org.openide.util.WeakListeners;
051:
052: import org.netbeans.modules.dbschema.*;
053:
054: /** Normal implementation of children list for a table element node.
055: */
056: public class SchemaChildren extends Children.Keys {
057: /** Converts property names to filter. */
058: protected static HashMap propToFilter;
059:
060: /** The table element whose subelements are represented. */
061: protected SchemaElement element;
062: /** Filter for elements, or <code>null</code> to disable. */
063: protected SchemaElementFilter filter;
064: /** Factory for creating new child nodes. */
065: protected DBElementNodeFactory factory;
066: /** Weak listener to the element and filter changes */
067: private PropertyChangeListener wPropL;
068: /** Listener to the element and filter changes. This reference must
069: * be kept to prevent the listener from finalizing when we are alive */
070: private DBElementListener propL;
071: /** Central memory of mankind is used when some elements are changed */
072: protected Collection[] cpl;
073: /** Flag saying whether we have our nodes initialized */
074: private boolean nodesInited = false;
075:
076: static {
077: propToFilter = new HashMap();
078: propToFilter.put(DBElementProperties.PROP_TABLES, new Integer(
079: TableElementFilter.TABLE));
080: propToFilter.put(DBElementProperties.PROP_COLUMNS, new Integer(
081: TableElementFilter.COLUMN));
082: propToFilter.put(DBElementProperties.PROP_INDEXES, new Integer(
083: TableElementFilter.INDEX));
084: propToFilter.put(DBElementProperties.PROP_KEYS, new Integer(
085: TableElementFilter.FK));
086: }
087:
088: /** Create class children with the default factory.
089: * The children are initially unfiltered.
090: * @param element attached class element (non-<code>null</code>)
091: */
092: public SchemaChildren(final SchemaElement element) {
093: this (DefaultDBFactory.READ_ONLY, element);
094: }
095:
096: /** Create class children.
097: * The children are initially unfiltered.
098: * @param factory the factory to use to create new children
099: * @param element attached class element (non-<code>null</code>)
100: */
101: public SchemaChildren(final DBElementNodeFactory factory,
102: final SchemaElement element) {
103: super ();
104: this .element = element;
105: this .factory = factory;
106: this .filter = null;
107: }
108:
109: /********** Implementation of filter cookie **********/
110:
111: /* @return The class of currently asociated filter or null
112: * if no filter is asociated with these children.
113: */
114: public Class getFilterClass() {
115: return SchemaElementFilter.class;
116: }
117:
118: /* @return The filter currently asociated with these children
119: */
120: public Object getFilter() {
121: return filter;
122: }
123:
124: /* Sets new filter for these children.
125: * @param filter New filter. Null == disable filtering.
126: */
127: public void setFilter(final Object filter) {
128: if (!(filter instanceof SchemaElementFilter))
129: throw new IllegalArgumentException();
130:
131: this .filter = (SchemaElementFilter) filter;
132: // change element nodes according to the new filter
133: if (nodesInited)
134: refreshAllKeys();
135: }
136:
137: // Children implementation ..............................................................
138:
139: /* Overrides initNodes to run the preparation task of the
140: * source element, call refreshKeys and start to
141: * listen to the changes in the element too. */
142: protected void addNotify() {
143: refreshAllKeys();
144:
145: // listen to the changes in the class element
146: if (wPropL == null) {
147: propL = new DBElementListener();
148: wPropL = WeakListeners.propertyChange(propL, element);
149: } else {
150: // #55249 - need to recreate the listener with the right element
151: wPropL = WeakListeners.propertyChange(propL, element);
152: }
153:
154: element.addPropertyChangeListener(wPropL);
155: nodesInited = true;
156: }
157:
158: protected void removeNotify() {
159: setKeys(java.util.Collections.EMPTY_SET);
160: nodesInited = false;
161: }
162:
163: /* Creates node for given key.
164: * The node is created using node factory.
165: */
166: protected Node[] createNodes(final Object key) {
167: if (key instanceof TableElement)
168: return new Node[] { factory
169: .createTableNode((TableElement) key) };
170:
171: // ?? unknown type
172: return new Node[0];
173: }
174:
175: /************** utility methods ************/
176:
177: /** Updates all the keys (elements) according to the current filter &
178: * ordering.
179: */
180: protected void refreshAllKeys() {
181: cpl = new Collection[getOrder().length];
182:
183: refreshKeys(SchemaElementFilter.TABLE);
184: }
185:
186: /** Updates all the keys with given filter.
187: */
188: protected void refreshKeys(int filter) {
189: int[] order = getOrder();
190: LinkedList keys = new LinkedList();
191:
192: // build ordered and filtered keys for the subelements
193: for (int i = 0; i < order.length; i++)
194: if (((order[i] & filter) != 0) || (cpl[i] == null))
195: keys.addAll(cpl[i] = getKeysOfType(order[i]));
196: else
197: keys.addAll(cpl[i]);
198:
199: // set new keys
200: setKeys(keys);
201: }
202:
203: /** Filters and returns the keys of specified type.
204: */
205: protected Collection getKeysOfType(final int elementType) {
206: LinkedList keys = new LinkedList();
207:
208: if ((elementType & SchemaElementFilter.TABLE) != 0)
209: filterModifiers(((SchemaElement) element).getTables(), keys);
210:
211: return keys;
212: }
213:
214: /** Filters MemberElements for modifiers, and adds them to the given collection.
215: */
216: private void filterModifiers(DBElement[] elements, Collection keys) {
217: int i, k = elements.length;
218:
219: for (i = 0; i < k; i++)
220: keys.add(elements[i]);
221: }
222:
223: /** Returns order form filter.
224: */
225: protected int[] getOrder() {
226: return (filter == null || (filter.getOrder() == null)) ? SchemaElementFilter.DEFAULT_ORDER
227: : filter.getOrder();
228: }
229:
230: // innerclasses ...........................................................................
231:
232: /** The listener for listening to the property changes in the filter.
233: */
234: private final class DBElementListener implements
235: PropertyChangeListener {
236: public DBElementListener() {
237: }
238:
239: /** This method is called when the change of properties occurs in the element.
240: * PENDING - (for Hanz - should be implemented better, change only the
241: * keys which belong to the changed property).
242: * -> YES MY LORD! ANOTHER WISH?
243: */
244: public void propertyChange(PropertyChangeEvent evt) {
245: Integer i = (Integer) propToFilter.get(evt
246: .getPropertyName());
247: if (i != null)
248: refreshKeys(i.intValue());
249: }
250: } // end of ElementListener inner class*/
251: }
|