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.openide.explorer.view;
042:
043: import org.openide.awt.HtmlRenderer;
044: import org.openide.awt.ListPane;
045: import org.openide.nodes.Node;
046: import java.awt.Component;
047: import java.awt.Container;
048: import java.util.logging.Level;
049: import java.util.logging.Logger;
050:
051: import javax.swing.*;
052: import javax.swing.tree.TreeCellRenderer;
053:
054: /** Default renderer for nodes. Can paint either Nodes directly or
055: * can be used to paint objects produced by NodeTreeModel, etc.
056: *
057: * @see org.openide.nodes.Node
058: *
059: * @author Jaroslav Tulach, Tim Boudreau
060: */
061: public class NodeRenderer extends Object implements TreeCellRenderer,
062: ListCellRenderer {
063: private static NodeRenderer instance = null;
064:
065: // ********************
066: // Support for dragging
067: // ********************
068:
069: /** Value of the cell with 'drag under' visual feedback */
070: private static VisualizerNode draggedOver;
071:
072: /** Flag indicating if to use big icons. */
073: private boolean bigIcons = false;
074: private HtmlRenderer.Renderer renderer = HtmlRenderer
075: .createRenderer();
076:
077: /** Creates default renderer. */
078: public NodeRenderer() {
079: }
080:
081: /** Creates renderer.
082: * @param bigIcons use big icons if possible
083: * @deprecated bigIcons was only used by IconView, and not used by that
084: * anymore. NodeRenderer will automatically detect if the view it's
085: * rendering for is an instance of IconView.
086: */
087: public @Deprecated
088: NodeRenderer(boolean bigIcons) {
089: this .bigIcons = bigIcons;
090: }
091:
092: /** Get the singleton instance used by all explorer views.
093: *
094: * @deprecated This method no longer returns a shared instance, as it
095: * caused problems with one view setting properties (such as enabled
096: * state) on the renderer and the renderer then being used in its altered
097: * state by a different view. Views should create their own instance of
098: * NodeRenderer instead.
099: */
100: public static @Deprecated
101: NodeRenderer sharedInstance() {
102: if (instance == null) {
103: instance = new NodeRenderer();
104: }
105:
106: IllegalStateException ise = new IllegalStateException(
107: "NodeRenderer."
108: + "sharedInstance() is deprecated. Create an instance of NodeRenderer"
109: + "instead");
110: Logger.getLogger(NodeRenderer.class.getName()).log(
111: Level.WARNING, null, ise);
112:
113: return instance;
114: }
115:
116: /** Finds the component that is capable of drawing the cell in a tree.
117: * @param value value can be either <code>Node</code>
118: * or a <code>VisualizerNode</code>.
119: * @return component to draw the value
120: */
121: public Component getTreeCellRendererComponent(JTree tree,
122: Object value, boolean sel, boolean expanded, boolean leaf,
123: int row, boolean hasFocus) {
124: VisualizerNode vis = findVisualizerNode(value);
125:
126: if (vis == draggedOver) {
127: sel = true;
128: }
129:
130: String text = vis.getHtmlDisplayName();
131: boolean isHtml = text != null;
132:
133: if (!isHtml) {
134: text = vis.getDisplayName();
135: }
136:
137: //Get our result value - really it is ren, but this call causes
138: //it to configure itself with the passed values
139: Component result = renderer.getTreeCellRendererComponent(tree,
140: text, sel, expanded, leaf, row, hasFocus);
141:
142: result.setEnabled(tree.isEnabled());
143: renderer.setHtml(isHtml);
144:
145: //Do our additional configuration - set up the icon and possibly
146: //do some hacks to make it look focused for TreeTableView
147: configureFrom(renderer, tree, expanded, sel, vis);
148:
149: return result;
150: }
151:
152: /** This is the only method defined by <code>ListCellRenderer</code>. We just
153: * reconfigure the <code>Jlabel</code> each time we're called.
154: */
155: public Component getListCellRendererComponent(JList list,
156: Object value, int index, boolean sel, boolean cellHasFocus) {
157: VisualizerNode vis = findVisualizerNode(value);
158:
159: if (vis == draggedOver) {
160: sel = true;
161: }
162:
163: String text = vis.getHtmlDisplayName();
164: boolean isHtml = text != null;
165:
166: if (!isHtml) {
167: text = vis.getDisplayName();
168: }
169:
170: //Get our result value - really it is ren, but this call causes
171: //it to configure itself with the passed values
172: Component result = renderer.getListCellRendererComponent(list,
173: text, index, sel, cellHasFocus
174: || (value == draggedOver));
175: renderer.setHtml(isHtml);
176: result.setEnabled(list.isEnabled());
177:
178: //Do our additional configuration - set up the icon and possibly
179: //do some hacks to make it look focused for TreeTableView
180: int iconWidth = configureFrom(renderer, list, false, sel, vis);
181:
182: boolean bigIcons = this .bigIcons || list instanceof ListPane;
183:
184: if (bigIcons) {
185: renderer.setCentered(true);
186: } else {
187: //Indent elements in a ListView/ChoiceView relative to their position
188: //in the node tree. Only does anything if you've subclassed and
189: //overridden createModel(). Does anybody do that?
190: if (list.getModel() instanceof NodeListModel
191: && (((NodeListModel) list.getModel()).getDepth() > 1)) {
192: int indent = iconWidth
193: * NodeListModel.findVisualizerDepth(list
194: .getModel(), vis);
195:
196: renderer.setIndent(indent);
197: }
198: }
199:
200: return result;
201: }
202:
203: /** Utility method which performs configuration which is common to all of the renderer
204: * implementations - sets the icon and focus properties on the renderer
205: * from the VisualizerNode.
206: *
207: */
208: private int configureFrom(HtmlRenderer.Renderer ren,
209: Container target, boolean useOpenedIcon, boolean sel,
210: VisualizerNode vis) {
211: Icon icon = vis.getIcon(useOpenedIcon, bigIcons);
212:
213: if (icon.getIconWidth() > 0) {
214: //Max annotated icon width is 24, so to have all the text and all
215: //the icons come out aligned, set the icon text gap to the difference
216: //plus a two pixel margin
217: ren.setIconTextGap(24 - icon.getIconWidth());
218: } else {
219: //If the icon width is 0, fill the space and add in
220: //the extra two pixels so the node names are aligned (btw, this
221: //does seem to waste a frightful amount of horizontal space in
222: //a tree that can use all it can get)
223: ren.setIndent(26);
224: }
225:
226: ren.setIcon(icon);
227:
228: if (target instanceof TreeTable.TreeTableCellRenderer) {
229: TreeTable tt = ((TreeTable.TreeTableCellRenderer) target)
230: .getTreeTable();
231: ren.setParentFocused(tt.hasFocus() || tt.isEditing());
232: }
233:
234: return (icon.getIconWidth() == 0) ? 24 : icon.getIconWidth();
235: }
236:
237: /** Utility method to find a visualizer node for the object passed to
238: * any of the cell renderer methods as the value */
239: private static final VisualizerNode findVisualizerNode(Object value) {
240: VisualizerNode vis = (value instanceof Node) ? VisualizerNode
241: .getVisualizer(null, (Node) value)
242: : (VisualizerNode) value;
243:
244: if (vis == null) {
245: vis = VisualizerNode.EMPTY;
246: }
247:
248: return vis;
249: }
250:
251: /** DnD operation enters. Update look and feel to the 'drag under' state.
252: * @param dragged the value of cell which should have 'drag under' visual feedback
253: */
254: static void dragEnter(Object dragged) {
255: draggedOver = (VisualizerNode) dragged;
256: }
257:
258: /** DnD operation exits. Revert to the normal look and feel. */
259: static void dragExit() {
260: draggedOver = null;
261: }
262: }
|