001 /*
002 * $Id: TreeCellContext.java 3424 2009-07-30 10:53:39Z kleopatra $
003 *
004 * Copyright 2008 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020 */
021 package org.jdesktop.swingx.renderer;
022
023 import java.awt.Color;
024 import java.awt.Component;
025 import java.awt.Graphics;
026
027 import javax.swing.Icon;
028 import javax.swing.JTree;
029 import javax.swing.UIManager;
030 import javax.swing.border.Border;
031 import javax.swing.border.LineBorder;
032 import javax.swing.plaf.basic.BasicGraphicsUtils;
033 import javax.swing.tree.TreePath;
034
035 import org.jdesktop.swingx.JXTree;
036
037 /**
038 * Tree specific <code>CellContext</code>.
039 *
040 * <ul>
041 * <li>PENDING: use focus border as returned from list or table instead of
042 * rolling its own? The missing ui-border probably is a consequence of the
043 * border hacking as implemented in core default renderer. SwingX has a
044 * composite default which should use the "normal" border.
045 * <li> PENDING: selection colors couple explicitly to SwingX - should we go JXTree as
046 * generic type?
047 * <li> PENDING: for a JXTree use the icons as returned by the xtree api?
048 * </ul>
049 */
050 public class TreeCellContext extends CellContext {
051 /** the icon to use for a leaf node. */
052 protected Icon leafIcon;
053
054 /** the default icon to use for a closed folder. */
055 protected Icon closedIcon;
056
057 /** the default icon to use for a open folder. */
058 protected Icon openIcon;
059
060 /** the border around a focused node. */
061 private Border treeFocusBorder;
062
063 /**
064 * Sets state of the cell's context. Note that the component might be null
065 * to indicate a cell without a concrete context. All accessors must cope
066 * with.
067 *
068 * @param component the component the cell resides on, might be null
069 * @param value the content value of the cell
070 * @param row the cell's row index in view coordinates
071 * @param column the cell's column index in view coordinates
072 * @param selected the cell's selected state
073 * @param focused the cell's focused state
074 * @param expanded the cell's expanded state
075 * @param leaf the cell's leaf state
076 */
077 public void installContext(JTree component, Object value, int row, int column,
078 boolean selected, boolean focused, boolean expanded, boolean leaf) {
079 this.component = component;
080 installState(value, row, column, selected, focused, expanded, leaf);
081 this.dropOn = checkDropOnState();
082 }
083
084 private boolean checkDropOnState() {
085 if ((getComponent() == null)) {
086 return false;
087 }
088 JTree.DropLocation dropLocation = getComponent().getDropLocation();
089 if (dropLocation != null
090 && dropLocation.getChildIndex() == -1
091 && getComponent().getRowForPath(dropLocation.getPath()) == row) {
092 return true;
093 }
094 return false;
095 }
096
097 @Override
098 public JTree getComponent() {
099 return (JTree) super.getComponent();
100 }
101
102 //------------------- accessors for derived state
103
104 /**
105 * Returns the treePath for the row or null if invalid.
106 *
107 */
108 public TreePath getTreePath() {
109 if (getComponent() == null) return null;
110 if ((row < 0) || (row >= getComponent().getRowCount())) return null;
111 return getComponent().getPathForRow(row);
112 }
113 /**
114 * {@inheritDoc}
115 * <p>
116 * PENDING: implement to return the tree cell editability!
117 */
118 @Override
119 public boolean isEditable() {
120 return false;
121 // return getComponent() != null ? getComponent().isCellEditable(
122 // getRow(), getColumn()) : false;
123 }
124
125 /**
126 * {@inheritDoc}
127 */
128 @Override
129 protected Color getSelectionBackground() {
130 Color selection = null;
131 if (isDropOn()) {
132 selection = getDropCellBackground();
133 if (selection != null) return selection;
134 }
135 if (getComponent() instanceof JXTree) {
136 return ((JXTree) getComponent()).getSelectionBackground();
137 }
138 return UIManager.getColor("Tree.selectionBackground");
139 }
140
141 /**
142 * {@inheritDoc}
143 */
144 @Override
145 protected Color getSelectionForeground() {
146 Color selection = null;
147 if (isDropOn()) {
148 selection = getDropCellForeground();
149 if (selection != null) return selection;
150 }
151 if (getComponent() instanceof JXTree) {
152 return ((JXTree) getComponent()).getSelectionForeground();
153 }
154 return UIManager.getColor("Tree.selectionForeground");
155 }
156
157 /**
158 * {@inheritDoc}
159 */
160 @Override
161 protected String getUIPrefix() {
162 return "Tree.";
163 }
164
165 /**
166 * Returns the default icon to use for leaf cell.
167 *
168 * @return the icon to use for leaf cell.
169 */
170 protected Icon getLeafIcon() {
171 return leafIcon != null ? leafIcon : UIManager
172 .getIcon(getUIKey("leafIcon"));
173 }
174
175 /**
176 * Returns the default icon to use for open cell.
177 *
178 * @return the icon to use for open cell.
179 */
180 protected Icon getOpenIcon() {
181 return openIcon != null ? openIcon : UIManager
182 .getIcon(getUIKey("openIcon"));
183 }
184
185 /**
186 * Returns the default icon to use for closed cell.
187 *
188 * @return the icon to use for closed cell.
189 */
190 protected Icon getClosedIcon() {
191 return closedIcon != null ? closedIcon : UIManager
192 .getIcon(getUIKey("closedIcon"));
193 }
194
195 /**
196 * {@inheritDoc}
197 * <p>
198 *
199 * Overridden to return a default depending for the leaf/open cell state.
200 */
201 @Override
202 public Icon getIcon() {
203 if (isLeaf()) {
204 return getLeafIcon();
205 }
206 if (isExpanded()) {
207 return getOpenIcon();
208 }
209 return getClosedIcon();
210 }
211
212 @Override
213 protected Border getFocusBorder() {
214 if (treeFocusBorder == null) {
215 treeFocusBorder = new TreeFocusBorder();
216 }
217 return treeFocusBorder;
218 }
219
220 /**
221 * Border used to draw around the content of the node. <p>
222 * PENDING: isn't that the same as around a list or table cell, but
223 * without a tree-specific key/value pair in UIManager?
224 */
225 public class TreeFocusBorder extends LineBorder {
226
227 private Color treeBackground;
228
229 private Color focusColor;
230
231 public TreeFocusBorder() {
232 super(Color.BLACK);
233 treeBackground = getBackground();
234 if (treeBackground != null) {
235 focusColor = new Color(~treeBackground.getRGB());
236 }
237 }
238
239 @Override
240 public void paintBorder(Component c, Graphics g, int x, int y,
241 int width, int height) {
242 Color color = UIManager.getColor("Tree.selectionBorderColor");
243 if (color != null) {
244 lineColor = color;
245 }
246 if (isDashed()) {
247 if (treeBackground != c.getBackground()) {
248 treeBackground = c.getBackground();
249 focusColor = new Color(~treeBackground.getRGB());
250 }
251
252 Color old = g.getColor();
253 g.setColor(focusColor);
254 BasicGraphicsUtils.drawDashedRect(g, x, y, width, height);
255 g.setColor(old);
256
257 } else {
258 super.paintBorder(c, g, x, y, width, height);
259 }
260
261 }
262
263 /**
264 * @return a boolean indicating whether the focus border
265 * should be painted dashed style.
266 */
267 private boolean isDashed() {
268 return Boolean.TRUE.equals(UIManager
269 .get("Tree.drawDashedFocusIndicator"));
270
271 }
272
273 /**
274 * {@inheritDoc}
275 */
276 @Override
277 public boolean isBorderOpaque() {
278 return false;
279 }
280
281 }
282
283 }