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-2007 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:
042: package org.netbeans.modules.search;
043:
044: import java.awt.Color;
045: import java.awt.Component;
046: import java.awt.Dimension;
047: import java.awt.Graphics;
048: import java.awt.Image;
049: import java.awt.Rectangle;
050: import java.beans.BeanInfo;
051: import java.io.CharConversionException;
052: import javax.swing.ImageIcon;
053: import javax.swing.JCheckBox;
054: import javax.swing.JComponent;
055: import javax.swing.JLabel;
056: import javax.swing.JTree;
057: import javax.swing.UIDefaults;
058: import javax.swing.UIManager;
059: import javax.swing.tree.TreeCellRenderer;
060: import javax.swing.tree.TreePath;
061: import org.openide.awt.HtmlRenderer;
062: import org.openide.filesystems.FileObject;
063: import org.openide.filesystems.FileUtil;
064: import org.openide.loaders.DataObject;
065: import org.openide.nodes.Node;
066: import org.openide.util.NbBundle;
067: import org.openide.util.Utilities;
068: import org.openide.xml.XMLUtil;
069:
070: /**
071: *
072: * @author Marian Petras
073: */
074: final class NodeRenderer extends JComponent implements TreeCellRenderer {
075:
076: /** */
077: private static Rectangle checkBounds;
078:
079: /** */
080: private final HtmlRenderer.Renderer nodeRenderer;
081: /** */
082: private final Image rootIconImage;
083: /** */
084: private final JCheckBox checkBox;
085:
086: /** */
087: private Image deletedObjectIconImage;
088: /** */
089: private String deletedObjectHtmlSuffix;
090: /**
091: * the component returned by
092: * {@link HtmlRenderer.Renderer#getTreeCellRendererComponent() getTreeCellRendererComponent()}
093: */
094: private Component stringDisplayer = new JLabel(" "); //NOI18N
095:
096: /**
097: *
098: */
099: NodeRenderer(final boolean withCheckBox) {
100: nodeRenderer = HtmlRenderer.createRenderer();
101: rootIconImage = Utilities.loadImage(
102: "org/netbeans/modules/search/res/find.gif", //NOI18N
103: true); //localized
104:
105: setLayout(null);
106: if (!withCheckBox) {
107: checkBox = null;
108: } else {
109: checkBox = new JCheckBox();
110: checkBox.setBorderPaintedFlat(true);
111:
112: Color c = UIManager.getColor("Tree.textBackground"); //NOI18N
113: if (c == null) {
114: //May be null on GTK L&F
115: c = Color.WHITE;
116: }
117: checkBox.setBackground(c);
118:
119: Dimension dim = checkBox.getPreferredSize();
120: checkBox.setPreferredSize(new Dimension(dim.width,
121: dim.height - 5));
122: }
123: }
124:
125: /**
126: */
127: public Component getTreeCellRendererComponent(JTree tree,
128: Object value, boolean selected, boolean expanded,
129: boolean leaf, int row, boolean hasFocus) {
130: final boolean isRoot = (row == 0);
131:
132: String text;
133: boolean isHtml;
134: Image iconImage;
135: boolean checked;
136:
137: if (isRoot) {
138: assert value instanceof ResultTreeModel;
139:
140: final ResultTreeModel resultTreeModel = (ResultTreeModel) value;
141: text = resultTreeModel.getRootDisplayName();
142: isHtml = false;
143: iconImage = rootIconImage;
144: checked = (checkBox != null) ? resultTreeModel.isSelected()
145: : false;
146:
147: } else if (value.getClass() == MatchingObject.class) {
148: final MatchingObject matchingObj = (MatchingObject) value;
149: final DataObject dataObj = (DataObject) matchingObj.object;
150: final boolean valid = matchingObj.isObjectValid();
151: if (valid) {
152: final Node node = dataObj.getNodeDelegate();
153: FileObject fileFolder = dataObj.getPrimaryFile()
154: .getParent();
155: String folderPath = FileUtil
156: .getFileDisplayName(fileFolder);
157: try {
158: text = node.getHtmlDisplayName();
159: isHtml = true;
160: if (text == null) {
161: text = XMLUtil.toElementContent(node
162: .getDisplayName());
163: }
164: text = text + " <font color='!"
165: + getFilePathColor() + "'>" //NOI18N
166: + XMLUtil.toElementContent(folderPath);
167: } catch (CharConversionException ex) {
168: text = node.getDisplayName() + ' ' + '('
169: + folderPath + ')';
170: isHtml = false;
171: }
172: iconImage = node.getIcon(BeanInfo.ICON_COLOR_16x16);
173: } else {
174: text = dataObj.getName() + getDeletedObjectHtmlSuffix();
175: isHtml = true;
176: iconImage = getDeletedObjectIconImage();
177: }
178: checked = (checkBox != null) ? matchingObj.isSelected()
179: : false;
180:
181: } else {
182: assert (value instanceof Node);
183:
184: final Node node = (Node) value;
185: text = node.getHtmlDisplayName();
186: isHtml = (text != null);
187: if (!isHtml) {
188: text = node.getDisplayName();
189: }
190: iconImage = node.getIcon(BeanInfo.ICON_COLOR_16x16);
191: if (checkBox == null) {
192: checked = false;
193: } else {
194: TreePath path = tree.getPathForRow(row);
195: if (path == null) { //surprisingly, this happens
196: checked = true;
197: } else {
198: MatchingObject matchingObj = (MatchingObject) path
199: .getPathComponent(1);
200: if (matchingObj.isUniformSelection()) {
201: checked = matchingObj.isSelected();
202: } else {
203: int parentPathRow = tree.getRowForPath(path
204: .getParentPath());
205: int index = row - parentPathRow - 1;
206: checked = matchingObj.isSubnodeSelected(index);
207: }
208: }
209: }
210: }
211:
212: stringDisplayer = nodeRenderer.getTreeCellRendererComponent(
213: tree, text, selected, expanded, leaf, row, hasFocus);
214:
215: nodeRenderer.setHtml(isHtml);
216: nodeRenderer.setIcon(new ImageIcon(iconImage));
217:
218: //HtmlRenderer does not tolerate null colors - real ones are needed to
219: //ensure fg/bg always diverge enough to be readable
220: if (stringDisplayer.getBackground() == null) {
221: stringDisplayer.setBackground(tree.getBackground());
222: }
223: if (stringDisplayer.getForeground() == null) {
224: stringDisplayer.setForeground(tree.getForeground());
225: }
226:
227: if (checkBox != null) {
228: checkBox.setSelected(checked);
229: return this ;
230: } else {
231: return stringDisplayer;
232: }
233: }
234:
235: /** name of the color to be used for displaying path to the found file */
236: private String filePathColorName;
237:
238: /** @see #filePathColor */
239: private String getFilePathColor() {
240: if (filePathColorName == null) {
241: UIDefaults uiDefaults = UIManager.getDefaults();
242: if (uiDefaults.getColor("Tree.selectionBackground").equals( //NOI18N
243: uiDefaults.getColor("controlShadow"))) { //NOI18N
244: filePathColorName = "Tree.selectionBorderColor"; //NOI18N
245: } else {
246: filePathColorName = "controlShadow"; //NOI18N
247: }
248: }
249: return filePathColorName;
250: }
251:
252: @Override
253: public void paint(Graphics g) {
254: Dimension checkDim = checkBox.getSize();
255: Dimension labelDim = stringDisplayer.getPreferredSize();
256:
257: int labelY = (checkDim.height >= labelDim.height) ? (checkDim.height - labelDim.height) / 2
258: : 0;
259: checkBox.paint(g);
260:
261: /*
262: * The stringDisplayer's bounds are set to (0, 0, 0, 0), although
263: * they have been set to reasonable values by doLayout().
264: * To work-around this, we translate the Graphics' origin
265: * to the desired location, paint the stringDisplayer and then
266: * return the Graphics' origin back.
267: */
268: assert stringDisplayer.getBounds().x == 0
269: && stringDisplayer.getBounds().y == 0;
270: g.translate(checkDim.width, labelY);
271: stringDisplayer.paint(g);
272: g.translate(-checkDim.width, -labelY);
273: }
274:
275: @Override
276: public Dimension getPreferredSize() {
277: stringDisplayer.setFont(getFont());
278:
279: Dimension prefSize = new Dimension(stringDisplayer
280: .getPreferredSize());
281: Dimension checkDim = checkBox.getPreferredSize();
282: prefSize.width += checkDim.width;
283: prefSize.height = Math.max(prefSize.height, checkDim.height);
284: return prefSize;
285: }
286:
287: @Override
288: public void doLayout() {
289: Dimension checkDim = checkBox.getPreferredSize();
290: Dimension labelDim = stringDisplayer.getPreferredSize();
291: int checkWidth = checkDim.width;
292: int checkHeight = checkDim.height;
293: int labelWidth = labelDim.width;
294: int labelHeight = labelDim.height;
295:
296: int heightDif = labelHeight - checkHeight;
297: int checkY = (heightDif > 2) ? heightDif / 2 - 1 : 0;
298: int labelY = (heightDif < 0) ? -heightDif / 2 : 0;
299:
300: checkBox.setBounds(0, checkY, checkWidth, checkHeight);
301: stringDisplayer.setBounds(checkWidth, labelY, labelWidth,
302: labelHeight);
303: if (checkBounds == null) {
304: checkBounds = checkBox.getBounds();
305: }
306: }
307:
308: private Image getDeletedObjectIconImage() {
309: if (deletedObjectIconImage == null) {
310: deletedObjectIconImage = Utilities.loadImage(
311: "org/netbeans/modules/search/res/invalid.png", //NOI18N
312: true); //localized
313: }
314: return deletedObjectIconImage;
315: }
316:
317: private String getDeletedObjectHtmlSuffix() {
318: if (deletedObjectHtmlSuffix == null) {
319: deletedObjectHtmlSuffix = " <font color=\"#ff0000\">" //NOI18N
320: + NbBundle
321: .getMessage(getClass(), "LBL_InvalidFile") //NOI18N
322: + "</font>"; //NOI18N
323: }
324: return deletedObjectHtmlSuffix;
325: }
326:
327: static Rectangle getCheckBoxRectangle() {
328: return (Rectangle) checkBounds.clone();
329: }
330: }
|