2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.groovy.groovyproject.ui;
44
import java.awt.Component;
45
import java.awt.Image;
46
import java.awt.Panel;
47
import java.awt.image.BufferedImage;
48
import java.beans.PropertyChangeEvent;
49
import java.beans.PropertyChangeListener;
50
import java.util.ArrayList;
51
import java.util.Collections;
52
import java.util.List;
53
import java.util.StringTokenizer;
54
import javax.swing.Icon;
55
import javax.swing.ImageIcon;
56
import javax.swing.event.ChangeEvent;
57
import javax.swing.event.ChangeListener;
58
import javax.swing.event.EventListenerList;
59
import org.netbeans.api.project.SourceGroup;
60
import org.netbeans.api.queries.VisibilityQuery;
61
import org.openide.filesystems.FileObject;
62
import org.openide.filesystems.FileUtil;
63
import org.openide.loaders.ChangeableDataFilter;
64
import org.openide.loaders.DataFilter;
65
import org.openide.loaders.DataFolder;
66
import org.openide.loaders.DataObject;
67
import org.openide.nodes.FilterNode;
68
import org.openide.nodes.Node;
69
import org.openide.nodes.NodeNotFoundException;
70
import org.openide.nodes.NodeOp;
71
import org.openide.util.Lookup;
72
import org.openide.util.WeakListeners;
73
import org.openide.util.lookup.Lookups;
74
import org.openide.util.lookup.ProxyLookup;
79
* Displays a package root in a tree.
83
final class TreeRootNode extends FilterNode implements PropertyChangeListener {
85
private static final DataFilter VISIBILITY_QUERY_FILTER = new VisibilityQueryDataFilter();
87
private final SourceGroup g;
89
public TreeRootNode(SourceGroup g) {
90
this(DataFolder.findFolder(g.getRootFolder()), g);
93
private TreeRootNode(DataFolder folder, SourceGroup g) {
94
super(folder.getNodeDelegate(),
95
folder.createNodeChildren(VISIBILITY_QUERY_FILTER),
96
new ProxyLookup(new Lookup[] {
97
folder.getNodeDelegate().getLookup(),
98
Lookups.singleton(new PathFinder(g)),
99
// no need for explicit search info
102
g.addPropertyChangeListener(WeakListeners.propertyChange(this, g));
105
/** Copied from PackageRootNode with modifications. */
106
private Image computeIcon(boolean opened, int type) {
107
Icon icon = g.getIcon(opened);
110
image = opened ? super.getOpenedIcon(type) : super.getIcon(type);
112
if (icon instanceof ImageIcon) {
113
image = ((ImageIcon) icon).getImage();
115
image = icon2image(icon);
121
private static Component CONVERTOR_COMPONENT = new Panel();
122
private static Image icon2image(Icon icon) {
123
int height = icon.getIconHeight();
124
int width = icon.getIconWidth();
126
BufferedImage bImage = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
127
icon.paintIcon( CONVERTOR_COMPONENT, bImage.getGraphics(), 0, 0 );
132
public Image getIcon(int type) {
133
return computeIcon(false, type);
136
public Image getOpenedIcon(int type) {
137
return computeIcon(true, type);
140
public String getName() {
144
public String getDisplayName() {
145
return g.getDisplayName();
148
public boolean canRename() {
152
public boolean canDestroy() {
156
public boolean canCut() {
160
public void propertyChange(PropertyChangeEvent ev) {
161
// XXX handle SourceGroup.rootFolder change too
162
fireNameChange(null, null);
163
fireDisplayNameChange(null, null);
165
fireOpenedIconChange();
168
/** Copied from PhysicalView and PackageRootNode. */
169
public static final class PathFinder {
171
private final SourceGroup g;
173
PathFinder(SourceGroup g) {
177
public Node findPath(Node rootNode, Object o) {
179
if (o instanceof FileObject) {
181
} else if (o instanceof DataObject) {
182
fo = ((DataObject) o).getPrimaryFile();
186
FileObject groupRoot = g.getRootFolder();
187
if (FileUtil.isParentOf(groupRoot, fo) /* && group.contains(fo) */) {
188
String relPath = FileUtil.getRelativePath(groupRoot, fo);
189
List/*<String>*/ path = new ArrayList();
190
StringTokenizer strtok = new StringTokenizer(relPath, "/"); // NOI18N
191
while (strtok.hasMoreTokens()) {
192
path.add(strtok.nextToken());
194
// XXX this is really ugly... cf. #44739 and #33330.
195
path.set(path.size() - 1, fo.getName());
198
return NodeOp.findPath(rootNode, Collections.enumeration(path));
199
} catch (NodeNotFoundException e) {
202
} else if (groupRoot.equals(fo)) {
211
/** Copied from PhysicalView. */
212
private static final class VisibilityQueryDataFilter implements ChangeListener, ChangeableDataFilter {
214
private static final long serialVersionUID = 1L; // in case a DataFolder.ClonedFilterHandle saves me
216
private final EventListenerList ell = new EventListenerList();
218
public VisibilityQueryDataFilter() {
219
VisibilityQuery.getDefault().addChangeListener(this);
222
public boolean acceptDataObject(DataObject obj) {
223
FileObject fo = obj.getPrimaryFile();
224
return VisibilityQuery.getDefault().isVisible(fo);
227
public void stateChanged(ChangeEvent e) {
228
Object[] listeners = ell.getListenerList();
229
ChangeEvent event = null;
230
for (int i = listeners.length - 2; i >= 0; i -= 2) {
231
if (listeners[i] == ChangeListener.class) {
233
event = new ChangeEvent(this);
235
((ChangeListener) listeners[i+1]).stateChanged(event);
240
public void addChangeListener(ChangeListener listener) {
241
ell.add(ChangeListener.class, listener);
244
public void removeChangeListener(ChangeListener listener) {
245
ell.remove(ChangeListener.class, listener);