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.palette;
043:
044: import java.awt.Image;
045: import java.awt.datatransfer.Transferable;
046: import java.awt.dnd.DropTargetDragEvent;
047: import java.beans.PropertyChangeEvent;
048: import java.beans.PropertyChangeListener;
049: import java.io.IOException;
050: import java.util.ArrayList;
051: import java.util.logging.Level;
052: import java.util.logging.Logger;
053: import javax.swing.Action;
054: import javax.swing.SwingUtilities;
055: import org.netbeans.spi.palette.DragAndDropHandler;
056: import org.openide.nodes.Index;
057: import org.openide.nodes.Node;
058: import org.openide.nodes.NodeEvent;
059: import org.openide.nodes.NodeListener;
060: import org.openide.nodes.NodeMemberEvent;
061: import org.openide.nodes.NodeReorderEvent;
062: import org.openide.util.Lookup;
063:
064: /**
065: * PaletteCategory implementation based on Nodes.
066: *
067: * @author S. Aubrecht
068: */
069: public class DefaultCategory implements Category, NodeListener {
070:
071: private Node categoryNode;
072: private ArrayList<CategoryListener> categoryListeners = new ArrayList<CategoryListener>(
073: 3);
074: private Item[] items;
075:
076: /**
077: * Creates a new instance of DefaultPaletteCategory
078: *
079: * @param categoryNode Node representing the category.
080: */
081: public DefaultCategory(Node categoryNode) {
082: this .categoryNode = categoryNode;
083: this .categoryNode.addNodeListener(this );
084: this .categoryNode
085: .addPropertyChangeListener(new PropertyChangeListener() {
086: public void propertyChange(PropertyChangeEvent evt) {
087: notifyListeners();
088: }
089: });
090: }
091:
092: public Image getIcon(int type) {
093: return categoryNode.getIcon(type);
094: }
095:
096: public void addCategoryListener(CategoryListener listener) {
097: synchronized (categoryListeners) {
098: categoryListeners.add(listener);
099: }
100: }
101:
102: public void removeCategoryListener(CategoryListener listener) {
103: synchronized (categoryListeners) {
104: categoryListeners.remove(listener);
105: }
106: }
107:
108: public Action[] getActions() {
109: return categoryNode.getActions(false);
110: }
111:
112: public String getShortDescription() {
113: return categoryNode.getShortDescription();
114: }
115:
116: public Item[] getItems() {
117: if (null == items) {
118: Node[] children = categoryNode.getChildren().getNodes(
119: DefaultModel.canBlock());
120: Item[] newItems = new Item[children.length];
121: for (int i = 0; i < children.length; i++) {
122: newItems[i] = new DefaultItem(children[i]);
123: }
124: items = newItems;
125: }
126: return items;
127: }
128:
129: public String getName() {
130: return categoryNode.getName();
131: }
132:
133: public String getDisplayName() {
134: return categoryNode.getDisplayName();
135: }
136:
137: protected void notifyListeners() {
138: SwingUtilities.invokeLater(new Runnable() {
139: public void run() {
140: CategoryListener[] listeners;
141: synchronized (categoryListeners) {
142: listeners = new CategoryListener[categoryListeners
143: .size()];
144: listeners = categoryListeners.toArray(listeners);
145: }
146: for (int i = 0; i < listeners.length; i++) {
147: listeners[i].categoryModified(DefaultCategory.this );
148: }
149: }
150: });
151: }
152:
153: /** Fired when a set of new children is added.
154: * @param ev event describing the action
155: */
156: public synchronized void childrenAdded(NodeMemberEvent ev) {
157: items = null;
158: notifyListeners();
159: }
160:
161: /** Fired when a set of children is removed.
162: * @param ev event describing the action
163: */
164: public synchronized void childrenRemoved(NodeMemberEvent ev) {
165: items = null;
166: notifyListeners();
167: }
168:
169: /** Fired when the order of children is changed.
170: * @param ev event describing the change
171: */
172: public synchronized void childrenReordered(NodeReorderEvent ev) {
173: items = null;
174: notifyListeners();
175: }
176:
177: /** Fired when the node is deleted.
178: * @param ev event describing the node
179: */
180: public synchronized void nodeDestroyed(NodeEvent ev) {
181: categoryNode.removeNodeListener(this );
182: }
183:
184: public void propertyChange(PropertyChangeEvent evt) {
185: if (Node.PROP_DISPLAY_NAME.equals(evt.getPropertyName())) {
186: notifyListeners();
187: }
188: }
189:
190: @Override
191: public boolean equals(Object obj) {
192: if (!(obj instanceof DefaultCategory))
193: return false;
194:
195: return categoryNode
196: .equals(((DefaultCategory) obj).categoryNode);
197: }
198:
199: public Transferable getTransferable() {
200: try {
201: return categoryNode.drag();
202: } catch (IOException ioE) {
203: Logger.getLogger(DefaultCategory.class.getName()).log(
204: Level.INFO, null, ioE);
205: }
206: return null;
207: }
208:
209: public Lookup getLookup() {
210: return categoryNode.getLookup();
211: }
212:
213: private int itemToIndex(Item item) {
214: if (null == item) {
215: return -1;
216: }
217: Node node = item.getLookup().lookup(Node.class);
218: if (null != node) {
219: Index order = categoryNode.getCookie(Index.class);
220: if (null != order) {
221: return order.indexOf(node);
222: }
223: }
224: return -1;
225: }
226:
227: public boolean dragOver(DropTargetDragEvent e) {
228: DragAndDropHandler handler = getDragAndDropHandler();
229: return handler.canDrop(getLookup(), e.getCurrentDataFlavors(),
230: e.getDropAction());
231: }
232:
233: public boolean dropItem(Transferable dropItem, int dndAction,
234: Item target, boolean dropBefore) {
235: int targetIndex = itemToIndex(target);
236: if (!dropBefore) {
237: targetIndex++;
238: }
239: DragAndDropHandler handler = getDragAndDropHandler();
240: boolean res = handler.doDrop(getLookup(), dropItem, dndAction,
241: targetIndex);
242: items = null;
243: return res;
244: }
245:
246: private DragAndDropHandler getDragAndDropHandler() {
247: return categoryNode.getLookup()
248: .lookup(DragAndDropHandler.class);
249: }
250:
251: @Override
252: public String toString() {
253: return categoryNode.getDisplayName();
254: }
255: }
|