/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun * Microsystems, Inc. All Rights Reserved. */ package org.openide.explorer.view; import java.awt.Component; import java.awt.Image; import java.beans.BeanInfo; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.WeakHashMap; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; import javax.swing.border.LineBorder; import javax.swing.border.EmptyBorder; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JTree; import javax.swing.ListCellRenderer; import javax.swing.UIManager; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellRenderer; import org.openide.ErrorManager; import org.openide.nodes.Node; import org.openide.util.Utilities; /** Default renderer for nodes. Can paint either Nodes directly or * can be used to paint objects produced by NodeTreeModel, etc. * * @see org.openide.nodes.Node * * @author Jaroslav Tulach */ public class NodeRenderer extends Object implements TreeCellRenderer, ListCellRenderer { /** Shared instance of <code>NodeRenderer</code>. */ private static NodeRenderer sharedInstance; /** Flag indicating if to use big icons. */ private boolean bigIcons; static Border emptyBorder = new EmptyBorder(1, 1, 1, 1); /** Creates default renderer. */ public NodeRenderer () { } /** Creates renderer. * @param bigIcons use big icons if possible */ public NodeRenderer (boolean bigIcons) { this.bigIcons = bigIcons; } /** Gets for one singleton <code>sharedInstance</code>. */ public static NodeRenderer sharedInstance () { if (sharedInstance == null) { sharedInstance = new NodeRenderer (); } return sharedInstance; } // // Rendering methods // /** Finds the component that is capable of drawing the cell in a tree. * @param value value can be either <code>Node</code> * or a <code>VisualizerNode</code>. * @return component to draw the value */ public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus ) { // accepting either Node or Visualizers VisualizerNode vis = (value instanceof Node) ? VisualizerNode.getVisualizer (null, (Node)value) : (VisualizerNode)value; return getTree().getTreeCellRendererComponent ( tree, value, sel, expanded, leaf, row, hasFocus ); } /** This is the only method defined by <code>ListCellRenderer</code>. We just * reconfigure the <code>Jlabel</code> each time we're called. */ public Component getListCellRendererComponent ( JList list, Object value, // value to display int index, // cell index boolean isSelected, // is the cell selected boolean cellHasFocus // the list and the cell have the focus ) { // accepting either Node or Visualizers VisualizerNode vis = (value instanceof Node) ? VisualizerNode.getVisualizer (null, (Node)value) : (VisualizerNode)value; if (vis == null) { vis = VisualizerNode.EMPTY; } ListCellRenderer r = bigIcons ? (ListCellRenderer)getPane() : getList(); return r.getListCellRendererComponent ( list, vis, index, isSelected, cellHasFocus ); } // ******************** // Support for dragging // ******************** /** Value of the cell with 'drag under' visual feedback */ private static VisualizerNode draggedOver; /** DnD operation enters. Update look and feel to the 'drag under' state. * @param value the value of cell which should have 'drag under' visual feedback */ static void dragEnter (Object dragged) { draggedOver = (VisualizerNode)dragged; } /** DnD operation exits. Revert to the normal look and feel. */ static void dragExit () { draggedOver = null; } // ******************** // Cache for ImageIcons // ******************** /** default icon to use when none is present */ private static final String DEFAULT_ICON = "org/openide/resources/defaultNode.gif"; // NOI18N /** loaded default icon */ private static ImageIcon defaultIcon; /** of icons used (Image, IconImage)*/ private static final WeakHashMap map = new WeakHashMap (); /** Loades default icon if not loaded. */ static ImageIcon getDefaultIcon () { if (defaultIcon == null) { defaultIcon = new ImageIcon(Utilities.loadImage(DEFAULT_ICON)); } return defaultIcon; } /** Finds imager for given resource. * @param image image to get * @return icon for the image */ static ImageIcon getIcon (Image image) { Reference ref = (Reference)map.get (image); ImageIcon icon = ref == null ? null : (ImageIcon)ref.get (); if (icon != null) { return icon; } icon = new ImageIcon (image); map.put (image, new WeakReference (icon)); return icon; } // // Renderers // private static NodeRenderer.Tree tree = null; private synchronized static NodeRenderer.Tree getTree () { if (tree == null) tree = new NodeRenderer.Tree (); return tree; } private static NodeRenderer.Pane pane = null; private synchronized static NodeRenderer.Pane getPane() { if (pane == null) pane = new NodeRenderer.Pane (); return pane; } private static NodeRenderer.List list = null; private synchronized static NodeRenderer.List getList() { if (list == null) list = new NodeRenderer.List (); return list; } /** Tree cell renderer. Accepts only <code>VisualizerNode</code> values. */ final static class Tree extends DefaultTreeCellRenderer { /** generated Serialized Version UID */ static final long serialVersionUID = -183570483117501696L; /** The borders for visual feedback during DnD operation. */ static Border activeBorder = new LineBorder(UIManager.getColor("List.focusCellHighlight")); // NOI18N /** Empty 0/1pixel border used by the Renderer */ static Border inactiveBorder; static { int width = DragDropUtilities.dragAndDropEnabled ? 1 : 0; inactiveBorder = new EmptyBorder(width, width, width, width); } /** @return Rendered cell component */ public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus ) { setEnabled(tree.isEnabled()); // accepts only VisualizerNode VisualizerNode vis = (VisualizerNode)value; Image iconImg; if (expanded) { iconImg = vis.node.getOpenedIcon(BeanInfo.ICON_COLOR_16x16); } else { iconImg = vis.node.getIcon(BeanInfo.ICON_COLOR_16x16); } // bugfix #28515, check if getIcon contract isn't broken if (iconImg == null) { ErrorManager.getDefault ().log (ErrorManager.WARNING, "Node " + vis.node.getName () + // NOI18N "[" +vis.node.getClass ()+ "] cannot return null icon. See Node.getIcon/getOpenedIcon contract."); // NOI18N } else { ImageIcon nodeicon = NodeRenderer.getIcon(iconImg); setIconTextGap (4 - nodeicon.getIconWidth() + ( nodeicon.getIconWidth() > 24 ? nodeicon.getIconWidth() : 24 ) ); setIcon(nodeicon); } setText(vis.getDisplayName ()); // provide "drag under" feedback if DnD operation is active // NOI18N if (vis == draggedOver) { sel = true; } this.hasFocus = hasFocus; selected = sel; if(sel) { setForeground(getTextSelectionColor()); } else { setForeground(getTextNonSelectionColor()); } return this; } protected void firePropertyChange(String name, Object old, Object nw) { // do really nothing! } } // End of class Tree. /** Implements a <code>ListCellRenderer</code> for rendering items * of a <code>List</code> containing <code>Node</code>s. * It displays the node's 16x16 icon and its display name. * * @author Ian Formanek */ static final class List extends JLabel implements ListCellRenderer { /** generated Serialized Version UID */ static final long serialVersionUID = -8387317362588264203L; /** Focused Node border. */ protected static Border focusBorder = new LineBorder(UIManager.getColor("List.focusCellHighlight")); // NOI18N public List() { setOpaque(true); } /** This is the only method defined by ListCellRenderer. We just * reconfigure the Jlabel each time we're called. */ public Component getListCellRendererComponent ( JList list, Object value, // value to display int index, // cell index boolean isSelected, // is the cell selected boolean cellHasFocus) // the list and the cell have the focus { VisualizerNode vis = (VisualizerNode)value; ImageIcon nodeicon = NodeRenderer.getIcon(vis.node.getIcon(BeanInfo.ICON_COLOR_16x16)); setIcon(nodeicon); setText(vis.getDisplayName ()); if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } setIconTextGap (4 - nodeicon.getIconWidth() + ( nodeicon.getIconWidth() > 24 ? nodeicon.getIconWidth() : 24 ) ); int delta = NodeListModel.findVisualizerDepth (list.getModel (), vis); Border border = (cellHasFocus || value == draggedOver) ? focusBorder : emptyBorder; if (delta > 0) { border = new CompoundBorder( new EmptyBorder (0, nodeicon.getIconWidth() * delta, 0, 0), border ); } setBorder(border); return this; } protected void firePropertyChange(String name, Object old, Object nw) { // do really nothing! } } // End of class List. /** List cell renderer which renders icon and display name from <code>VisualizerNode</code>. */ final static class Pane extends JLabel implements ListCellRenderer { /** generated Serialized Version UID */ static final long serialVersionUID = -5100925551665387243L; /** Focused Node border. */ static Border focusBorder = LineBorder.createBlackLineBorder(); /** Creates a new NetbeansListCellRenderer */ public Pane () { setOpaque(true); setVerticalTextPosition(JLabel.BOTTOM); setHorizontalAlignment(JLabel.CENTER); setHorizontalTextPosition(JLabel.CENTER); } /** This is the only method defined by ListCellRenderer. We just * reconfigure the Jlabel each time we're called. * @param list the JList * @param value the value returned by list.getModel().getElementAt(index) * @param index the cells index * @param isSelected <code>true</code> if the specified cell was selected * @param cellHasFocus <code>true</code> if the specified cell has the focus * @return a component whose paint() method will render the specified value */ public Component getListCellRendererComponent ( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus ) { VisualizerNode vis = (VisualizerNode)value; setIcon(NodeRenderer.getIcon(vis.node.getIcon(BeanInfo.ICON_COLOR_32x32))); setText(vis.getDisplayName ()); if (isSelected){ setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } setBorder(cellHasFocus ? focusBorder : emptyBorder); return this; } protected void firePropertyChange(String name, Object old, Object nw) { // do really nothing! } } // End of class Pane. }