001: /*
002: * @(#)StyledLabel.java 9/6/2005
003: *
004: * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
005: */
006: package com.jidesoft.swing;
007:
008: import com.jidesoft.plaf.LookAndFeelFactory;
009: import com.jidesoft.plaf.UIDefaultsLookup;
010:
011: import javax.swing.*;
012: import java.util.List;
013: import java.util.Vector;
014:
015: /**
016: * <code>StyledLabel</code> is a special JLabel which can display text in different styles.
017: * It is a component between JLabel and JTextPane. JLabel is simple, fast but has limited features.
018: * For example, you can't use different color to draw the text. You may argue JLabel can use HTML
019: * tag to display text in different colors. However there are two main reasons to use StyledLabel.
020: * First of all, StyledLabel is very fast and almost as fast as JLabel with plain text. HTML JLabel is very slow.
021: * You can see StyledLabelPerformanceDemo.java in examples\B15. StyledLabel folder to see a performace test of HTML JLabel
022: * and StyledLabel.
023: * HTML JLabel is also buggy. See bug report at <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4373575">http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4373575</a>.
024: * Sun claimed it is fixed but it is not as another user pointed it out at the end. If you run the test case provided by original submitter, you
025: * will immediately notice the tree node disappeared when you click on the tree nodes.
026: * This bug is actually one of the main reasons we decided to create StyledLabel.
027: * JTextPane is powerful and can display text in different color. But in the cases
028: * like cell renderer, JTextPane is obviously an overkill.
029: * <p/>
030: * StyledLabel sits between JLabel and JTextPane and provides a very simple and fast way to
031: * display text in different color and style. It can also support decorations using all kinds of line styles.
032: * <p/>
033: * All the methods on JLabel still work as before. The methods added in StyledLabel are several methods for StyleRange, such as
034: * {@link #setStyleRange(StyleRange)}, {@link #setStyleRanges(StyleRange[])}, {@link #clearStyleRange(StyleRange)}, and {@link #clearStyleRanges()}.
035: * <p/>
036: * This is one thing about StyleRange that you should be aware of, which could be considered as
037: * a future enhancement item, is that the StyleRanges can't overlap with each other.
038: * For example, if you defined a StyleRange that covers from index 0 to index 3,
039: * you can't define any other StyleRange that overlaps with the first one.
040: * If you do so, the second StyleRange will be ignored.
041: * <p/>
042: * We borrowed some ideas from SWT's StyledText when we designed StyledLabel, especially StyleRange concept.
043: * Saying that, the features of the two components are not exactly the same since the purpose of the
044: * two components are quite different.
045: */
046: public class StyledLabel extends JLabel {
047:
048: private static final String uiClassID = "StyledLabelUI";
049:
050: /**
051: * The list of StyleRanges.
052: */
053: private List _styleRanges;
054:
055: private boolean _ignoreColorSettings;
056:
057: public static final String PROPERTY_STYLE_RANGE = "styleRange";
058: public static final String PROPERTY_IGNORE_COLOR_SETTINGS = "ignoreColorSettings";
059:
060: public StyledLabel() {
061: }
062:
063: public StyledLabel(Icon image) {
064: super (image);
065: }
066:
067: public StyledLabel(Icon image, int horizontalAlignment) {
068: super (image, horizontalAlignment);
069: }
070:
071: public StyledLabel(String text) {
072: super (text);
073: }
074:
075: public StyledLabel(String text, int horizontalAlignment) {
076: super (text, horizontalAlignment);
077: }
078:
079: public StyledLabel(String text, Icon icon, int horizontalAlignment) {
080: super (text, icon, horizontalAlignment);
081: }
082:
083: /**
084: * Resets the UI property to a value from the current look and
085: * feel.
086: *
087: * @see JComponent#updateUI
088: */
089: @Override
090: public void updateUI() {
091: if (UIDefaultsLookup.get(uiClassID) == null) {
092: LookAndFeelFactory.installJideExtension();
093: }
094: setUI(UIManager.getUI(this ));
095: }
096:
097: /**
098: * Returns a string that specifies the name of the L&F class
099: * that renders this component.
100: *
101: * @return the string "StyledLabelUI"
102: * @see JComponent#getUIClassID
103: * @see UIDefaults#getUI
104: */
105: @Override
106: public String getUIClassID() {
107: return uiClassID;
108: }
109:
110: /**
111: * Adds a StyleRange into this <code>StyledLabel</code>.
112: *
113: * @param styleRange the new StyleRange.
114: */
115: public void addStyleRange(StyleRange styleRange) {
116: if (styleRange == null) {
117: throw new IllegalArgumentException(
118: "StyleRange cannot be null.");
119: }
120: List ranges = internalGetStyleRanges();
121: for (int i = 0; i < ranges.size(); i++) {
122: StyleRange range = (StyleRange) ranges.get(i);
123: if (range.getStart() == styleRange.getStart()
124: && range.getStart() == styleRange.getStart()) {
125: ranges.remove(i);
126: }
127: }
128: internalGetStyleRanges().add(styleRange);
129: firePropertyChange(PROPERTY_STYLE_RANGE, null, styleRange);
130: }
131:
132: /**
133: * @deprecated use {@link #addStyleRange(StyleRange)} instead. The method name "set" usually means
134: * clear all previous style range and set this as the new one, which is not correct.
135: * So using method name "add" makes more sense.
136: */
137: public void setStyleRange(StyleRange styleRange) {
138: addStyleRange(styleRange);
139: }
140:
141: /**
142: * Clears all the old StyleRanges and adds a list of StyleRanges into this <code>StyledLabel</code>.
143: *
144: * @param styleRanges set the StyleRanges.
145: */
146: public void setStyleRanges(StyleRange[] styleRanges) {
147: internalGetStyleRanges().clear();
148: addStyleRanges(styleRanges);
149: }
150:
151: /**
152: * Adds a list of StyleRanges into this <code>StyledLabel</code>.
153: *
154: * @param styleRanges an array of StyleRanges.
155: */
156: public void addStyleRanges(StyleRange[] styleRanges) {
157: if (styleRanges != null) {
158: for (int i = 0; i < styleRanges.length; i++) {
159: internalGetStyleRanges().add(styleRanges[i]);
160: }
161: firePropertyChange(PROPERTY_STYLE_RANGE, null, styleRanges);
162: } else {
163: firePropertyChange(PROPERTY_STYLE_RANGE, null, null);
164: }
165: }
166:
167: /**
168: * Gets the array of StyledText.
169: *
170: * @return the array of StyledText.
171: */
172: public StyleRange[] getStyleRanges() {
173: List list = internalGetStyleRanges();
174: return (StyleRange[]) list.toArray(new StyleRange[list.size()]);
175: }
176:
177: private List internalGetStyleRanges() {
178: if (_styleRanges == null) {
179: _styleRanges = new Vector();
180: }
181: return _styleRanges;
182: }
183:
184: /**
185: * Removes the StyleRange.
186: *
187: * @param styleRange the StyleRange to be removed.
188: */
189: public void clearStyleRange(StyleRange styleRange) {
190: if (internalGetStyleRanges().remove(styleRange)) {
191: firePropertyChange(PROPERTY_STYLE_RANGE, styleRange, null);
192: }
193: }
194:
195: /**
196: * Clears all the StyleRanges.
197: */
198: public void clearStyleRanges() {
199: internalGetStyleRanges().clear();
200: firePropertyChange(PROPERTY_STYLE_RANGE, null, null);
201: }
202:
203: /**
204: * StyleRange could define color for the text and lines. However
205: * when StyledLabel is used in cell renderer, the color could be conflict with
206: * selection color. So usually when it is used as cell renderer, the color defined in StyleRange should be
207: * ignored when cell is selected. If so, the foreground is used to paint all text and lines.
208: *
209: * @return true if the color defined by StyleRange should be ignored.
210: */
211: public boolean isIgnoreColorSettings() {
212: return _ignoreColorSettings;
213: }
214:
215: /**
216: * Sets if the color defined by StyleRange should be ignored.
217: * This flag is used when StyledLabel is used as a selected cell renderer.
218: * Since the selection usually has it own unique selection background and foreground,
219: * the color setting set on this StyledLabel could be unreadable on the selection background,
220: * it'd better if we don't use any color settings in this case.
221: *
222: * @param ignoreColorSettings true or false.
223: */
224: public void setIgnoreColorSettings(boolean ignoreColorSettings) {
225: boolean old = _ignoreColorSettings;
226: if (old != ignoreColorSettings) {
227: _ignoreColorSettings = ignoreColorSettings;
228: firePropertyChange(PROPERTY_IGNORE_COLOR_SETTINGS, old,
229: ignoreColorSettings);
230: }
231: }
232: }
|