001    /*
002     * $Id: ConditionalHighlighter.java,v 1.11 2006/05/14 15:55:52 dmouse Exp $
003     *
004     * Copyright 2004 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    
022    package org.jdesktop.swingx.decorator;
023    
024    import java.awt.Color;
025    import java.awt.Component;
026    
027    /**
028     * ConditionalHighlighter.
029     * 
030     * 
031     * @author Ramesh Gupta
032     */
033    public abstract class ConditionalHighlighter extends Highlighter {
034        protected int               testColumn = 0;         // always in model coordinates
035        protected int               highlightColumn = -1;   // always in model coordinates
036    
037        // TODO JW ?? - changed from 255 to 256 to not be "on" by default...
038        protected int               mask = 256;
039    
040        public ConditionalHighlighter() {
041            // default constructor
042        }
043    
044        /**
045         * <p>Constructs a <code>ConditionalHighlighter</code> instance with the
046         * specified background and foreground colors that will be used to highlight
047         * the renderer component for a cell in the specified highlightColumn of any
048         * row if and only if {@link #needsHighlight needsHighlight} returns true
049         * for the adapter that identifies that cell.</p>
050         *
051         * @param cellBackground background color for highlighted cells, or null, if
052         *          background should not be changed
053         * @param cellForeground foreground color for highlighted cells, or null, if
054         *          foreground should not be changed
055         * @param testColumn column whose value is to be tested to determine if a
056         *          cell <em>should</em> be highlighted
057         * @param highlightColumn column whose index is used to determine if a cell
058         *          <em>could</em> be highlighted; may be a valid column index in model
059         *          coordinates, or -1 to indicate all columns
060         */
061        public ConditionalHighlighter(Color cellBackground, Color cellForeground,
062                                      int testColumn, int highlightColumn) {
063            super(cellBackground, cellForeground);
064            this.testColumn = testColumn;
065            this.highlightColumn = highlightColumn;
066        }
067    
068        /**
069         * TODO: JW ??
070         */
071        public void setMask(int alpha) {
072            mask = alpha;
073            fireStateChanged();
074        }
075    
076        /**
077         * TODO: JW ??
078         * @return mask
079         */
080        public int getMask() {
081            return mask;
082        }
083    
084        /**
085         * Performs a conditional highlight. Calls {@link #doHighlight doHighlight} if
086         * and only if {@link #needsHighlight needsHighlight} returns true.
087         *
088         * @param renderer
089         * @param adapter
090         * @return the highlighted component
091         */
092        @Override
093        public Component highlight(Component renderer, ComponentAdapter adapter) {
094            if (needsHighlight(adapter)) {
095                return doHighlight(renderer, adapter);
096            }
097            else if (getMask() < 256) {
098                return doMask(renderer, adapter);
099            }
100            return renderer;
101        }
102    
103        /**
104         * TODO: ??
105         * 
106         * @param renderer
107         * @param adapter
108         * @return renderer
109         */
110        protected Component doMask(Component renderer, ComponentAdapter adapter) {
111    
112            maskBackground(renderer, adapter);
113            maskForeground(renderer, adapter);
114            // and so on...
115    
116            return renderer;
117        }
118    
119        /**
120         * TODO: ??
121         */
122        protected void maskBackground(Component renderer, ComponentAdapter adapter) {
123            Color seed = renderer.getBackground();
124            Color color = adapter.isSelected() ? computeSelectedBackground(seed) : seed;
125            // fix issue#21-swingx: foreground of renderers can be null
126            if (color != null) {
127                renderer.setBackground(
128                                   new Color((getMask() << 24) | (color.getRGB() & 0x00FFFFFF), true));
129            }
130        }
131    
132        /**
133         * TODO: ??
134         * @param renderer
135         * @param adapter
136         */
137        protected void maskForeground(Component renderer, ComponentAdapter adapter) {
138            Color seed = renderer.getForeground();
139            Color color = adapter.isSelected() ? computeSelectedForeground(seed) : seed;
140            // fix issue#21-swingx: foreground of renderers can be null
141            if (color != null) {
142                renderer.setForeground(
143                                   new Color((getMask() << 24) | (color.getRGB() & 0x00FFFFFF), true));
144        
145            }
146        }
147       
148        @Override
149        @Deprecated
150        protected Color computeSelectedForeground(Color seed) {
151            return getSelectedForeground() == null ? 
152                    seed == null ? null : seed.brighter() : getSelectedForeground();
153        }
154    
155        public int getTestColumnIndex() {
156            return testColumn;
157        }
158    
159        public void setTestColumnIndex(int columnIndex) {
160            this.testColumn = columnIndex;
161            fireStateChanged();
162        }
163    
164        public int getHighlightColumnIndex() {
165            return highlightColumn;
166        }
167    
168        public void setHighlightColumnIndex(int columnIndex) {
169            this.highlightColumn = columnIndex;
170            fireStateChanged();
171        }
172    
173        /**
174         * Checks if the cell identified by the specified adapter is a potential
175         * candidate for highlighting, and returns true if so; otherwise, it returns false.
176         *
177         * @param adapter
178         * @return true if the cell identified by the specified adapter needs
179         *          highlight; false otherwise
180         */
181        protected boolean needsHighlight(ComponentAdapter adapter) {
182            // Before running test(), quickly check if the cell in the current
183            // adapter is a potential candidate for highlighting. If so, run the test.
184            // highlightColumn is always in "model" coordinates, but adapter.column
185            // is in "view" coordinates. So, convert before comparing.
186            if ((highlightColumn < 0) ||
187                (highlightColumn == adapter.viewToModel(adapter.column))) {
188                return test(adapter);
189            }
190            return false;   // cell is not a candidate for decoration;
191        }
192    
193        /**
194         * Tests if the cell identified by the specified adapter should actually be
195         * highlighted, and returns true if so; otherwise, it returns false.
196         *
197         * @param adapter
198         * @return true if the test succeeds; false otherwise
199         */
200        protected abstract boolean test(ComponentAdapter adapter);
201    
202    }