001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.struct;
025:
026: import jacareto.record.Recordable;
027: import jacareto.system.Environment;
028: import jacareto.toolkit.EnhancedHashtable;
029: import jacareto.toolkit.ResourceLoader;
030:
031: import java.awt.Color;
032: import java.awt.Component;
033: import java.awt.Dimension;
034: import java.awt.Font;
035: import java.awt.Graphics;
036: import java.awt.Image;
037: import java.awt.image.BufferedImage;
038:
039: import java.util.Enumeration;
040: import java.util.Hashtable;
041:
042: import javax.swing.Icon;
043: import javax.swing.JComponent;
044: import javax.swing.JLabel;
045: import javax.swing.JTree;
046: import javax.swing.tree.DefaultTreeCellRenderer;
047: import javax.swing.tree.TreeCellRenderer;
048:
049: /**
050: * The cell renderer for structure elements.
051: *
052: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
053: * @version 1.01
054: */
055: public class StructureTreeCellRenderer extends JComponent implements
056: TreeCellRenderer {
057: /** The text color for recordables. */
058: private static final Color recordableTextColor = Color.black; /*new Color(0, 0, 200);*/
059:
060: /** The text color for all other structure elements. */
061: private static final Color structureElementTextColor = Color.black;
062:
063: /** The text color for search hits. */
064: private static final Color searchHitTextColor = new Color(0, 0, 255);
065:
066: /** The text color for parents of search hits. */
067: private static final Color parentOfSearchHitTextColor = new Color(
068: 0, 200, 0);
069:
070: /** The focus color. */
071: private static final Color focusColor = new Color(49, 106, 197);
072:
073: /** The text gap. */
074: private static final int textGap = 3;
075:
076: /** The gap between image and text. */
077: private static final int textImageGap = 5;
078:
079: /** The font for search hits. */
080: private static Font searchHitTextFont;
081:
082: /** The font for parents of search hits. */
083: private static Font parentOfSearchHitTextFont;
084:
085: /** The font for recordables. */
086: private static Font recordableFont;
087:
088: /** The font for all other structure elements. */
089: private static Font structureElementFont;
090:
091: /** Whether or not the element has the focus. */
092: private boolean hasFocus;
093:
094: /** Whether or not the element has an icon. */
095: private boolean hasIcon;
096:
097: /** Whether or not the element has an image. */
098: private boolean hasImage;
099:
100: /** The text. */
101: private String text;
102:
103: /** Whether or not the element is selected. */
104: private boolean isSelected;
105:
106: /** The text color. */
107: private Color textColor;
108:
109: /** The text offset, depending on the icon width. */
110: private int textOffset;
111:
112: /** The default icons. */
113: private Icon defaultLeafIcon;
114:
115: /** The default icons. */
116: private Icon defaultClosedIcon;
117:
118: /** The default icons. */
119: private Icon defaultOpenIcon;
120:
121: /** Maps classnames to icon filenames. */
122: private Hashtable classToFilename;
123:
124: /** The customized icons. */
125: private Hashtable filenameToIcon;
126:
127: /** The actual image. */
128: private Image image;
129:
130: /** The actual icon. */
131: private Icon icon;
132:
133: /** The environment. */
134: private Environment env;
135:
136: /**
137: * Creates a new cell renderer.
138: *
139: * @param env the environment
140: */
141: public StructureTreeCellRenderer(Environment env) {
142: this .env = env;
143:
144: recordableFont = new JLabel().getFont().deriveFont(14f);
145: structureElementFont = recordableFont; /*.deriveFont(Font.BOLD);*/
146: searchHitTextFont = recordableFont;
147: parentOfSearchHitTextFont = recordableFont;
148:
149: // get default icons
150: DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
151: defaultLeafIcon = defaultRenderer.getDefaultLeafIcon();
152: defaultClosedIcon = defaultRenderer.getDefaultClosedIcon();
153: defaultOpenIcon = defaultRenderer.getDefaultOpenIcon();
154:
155: // load the customized icons
156: loadIcons();
157: }
158:
159: /**
160: * Returns the tree cell renderer component.
161: *
162: * @param tree the tree
163: * @param value the node
164: * @param selected whether or not the node is selected
165: * @param expanded whether or not the node is expanded
166: * @param leaf whether or not the node is a leaf
167: * @param row the number of the row
168: * @param hasFocus whether or not the node has the focus
169: *
170: * @return the renderer component
171: */
172: public Component getTreeCellRendererComponent(JTree tree,
173: Object value, boolean selected, boolean expanded,
174: boolean leaf, int row, boolean hasFocus) {
175: StructureElement element = (StructureElement) value;
176:
177: if (element.isSearchHit()) {
178: setFont(searchHitTextFont);
179: textColor = searchHitTextColor;
180: } else if (element.isParentOfSearchHit()) {
181: setFont(parentOfSearchHitTextFont);
182: textColor = parentOfSearchHitTextColor;
183: } else if (value instanceof Recordable) {
184: setFont(recordableFont);
185: textColor = recordableTextColor;
186: } else {
187: setFont(structureElementFont);
188: textColor = structureElementTextColor;
189: }
190:
191: this .text = element.toShortString();
192: this .hasFocus = hasFocus;
193: this .isSelected = selected;
194:
195: // Defining the icon
196: this .hasIcon = false;
197: this .hasImage = false;
198:
199: Class nodeClass = element.getClass();
200: String nodeClassname = nodeClass.getName();
201:
202: // Find superclass if class is not known
203: if (!classToFilename.containsKey(nodeClassname)) {
204: Enumeration keys = classToFilename.keys();
205:
206: while (keys.hasMoreElements()) {
207: String super Class = (String) keys.nextElement();
208:
209: try {
210: if (Class.forName(super Class).isAssignableFrom(
211: nodeClass)) {
212: classToFilename.put(nodeClassname,
213: classToFilename.get(super Class));
214:
215: break;
216: }
217: } catch (ClassNotFoundException cnfex) {
218: ;
219: }
220: }
221: }
222:
223: if (classToFilename.containsKey(nodeClassname)) {
224: image = (Image) filenameToIcon.get(classToFilename
225: .get(nodeClassname));
226: hasImage = true;
227: } else {
228: if (leaf) {
229: icon = defaultLeafIcon;
230: hasIcon = true;
231: } else {
232: if (expanded) {
233: icon = defaultOpenIcon;
234: hasIcon = true;
235: } else {
236: icon = defaultClosedIcon;
237: hasIcon = true;
238: }
239: }
240: }
241:
242: // Calculating the overall width
243: textOffset = 0;
244:
245: if (hasIcon) {
246: textOffset = icon.getIconWidth() + textImageGap;
247: } else if (hasImage) {
248: textOffset = image.getWidth(null) + textImageGap;
249: }
250:
251: int width = textOffset
252: + getFontMetrics(getFont()).stringWidth(text)
253: + (2 * textGap);
254: setPreferredSize(new Dimension(width, 16));
255:
256: return this ;
257: }
258:
259: /**
260: * Paints the component.
261: *
262: * @param g the graphics object
263: */
264: public void paintComponent(Graphics g) {
265: int width = getWidth();
266: int height = getHeight();
267:
268: if (hasImage) {
269: g.drawImage(image, 0, 0, null);
270: } else if (hasIcon) {
271: icon.paintIcon(this , g, 0, 0);
272: }
273:
274: if (hasFocus || isSelected) {
275: g.setColor(focusColor);
276: g.fillRect(textOffset, 0, width - textOffset, height);
277: }
278:
279: if (text != null) {
280: int stringWidth = g.getFontMetrics().stringWidth(text);
281: width += stringWidth;
282: setPreferredSize(new Dimension(stringWidth, getHeight()));
283:
284: if (hasFocus || isSelected) {
285: g.setColor(Color.white);
286: } else {
287: g.setColor(textColor);
288: }
289:
290: g.drawString(text, textOffset + textGap, height - 3);
291: }
292: }
293:
294: /**
295: * Loads the customized icons
296: */
297: private void loadIcons() {
298: String iconDir = env.getFiles().getDir("TREE_ICONS_DIR")
299: .toString();
300: classToFilename = env.getCustomization().getMap(
301: "StructureTreeIcons.Files", new EnhancedHashtable());
302: filenameToIcon = new Hashtable();
303:
304: // Load the icons
305: Enumeration keys = classToFilename.keys();
306:
307: while (keys.hasMoreElements()) {
308: String className = (String) keys.nextElement();
309: String filename = (String) classToFilename.get(className);
310:
311: if (!filenameToIcon.containsKey(filename)) {
312: String file = iconDir + "/" + filename;
313: BufferedImage loadedImage = ResourceLoader
314: .getBufferedImage(file);
315:
316: if (loadedImage != null) {
317: filenameToIcon.put(filename, loadedImage);
318: }
319: }
320: }
321: }
322: }
|