1 /***
2 * DefaultTableColorModel.java
3 *
4 * This file is part of the creme library.
5 * The creme library intends to ease the development effort of large
6 * applications by providing easy to use support classes.
7 *
8 * Copyright (C) 2002 Denis Bregeon
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * contact information: dbregeon@sourceforge.net
25 */
26 package org.jcreme.swing.table.colormodel;
27
28 import java.awt.Color;
29 import java.util.EventListener;
30
31 import javax.swing.event.EventListenerList;
32 import javax.swing.table.TableModel;
33
34 import org.jcreme.swing.table.TableColorModel;
35 import org.jcreme.swing.table.TableColorModelEvent;
36 import org.jcreme.swing.table.TableColorModelListener;
37
38 /***
39 * This a basic implementation of the TableColorModel interface. The only color
40 * effect of this class is to ensure a minimum "distance" between the foreground
41 * and background colors. Other implementations may derive from this class.
42 *
43 * @author $Author: dbregeon $
44 * @version $Revision: 1.3 $
45 */
46 public class DefaultTableColorModel implements TableColorModel {
47 /***
48 * This is the minimum "distance" between the background and the foreground
49 * colors. This distance ensures that the foreground text is always visible.
50 */
51 protected static final int MINIMUM_COLOR_DISTANCE = 170;
52
53 /***
54 * The data to use when determining a color.
55 */
56 private transient TableModel dataModel = null;
57
58 /***
59 * The list of listeners registered for the TableColorModelChanged events.
60 */
61 private final EventListenerList listenerList = new EventListenerList();
62
63 /***
64 * Gets the list of the listeners registered for the modifications of the
65 * color scheme.
66 *
67 * @param listenerType
68 * The class of listeners to retrieve.
69 * @return The list of all listeners of the given type registered in the
70 * list.
71 */
72 public EventListener[] getListeners(Class listenerType) {
73 return this.listenerList.getListeners(listenerType);
74 }
75
76 /***
77 * Gives access to the background color of a cell.
78 *
79 * @param row
80 * the cell's row.
81 * @param column
82 * the cell's column.
83 * @param selected
84 * whether the cell is currently selected or not.
85 * @param renderer
86 * the renderer used to display the cell.
87 * @return the background color for the cell.
88 */
89 public Color getBackgroundColor(int row, int column, boolean selected,
90 java.awt.Component renderer) {
91 return renderer.getBackground();
92 }
93
94 /***
95 * Fires a TableColorModelEvent telling registered listeners that the color
96 * scheme has changed.
97 *
98 * @param e
99 * The event describing the changes.
100 */
101 protected void fireTableColorModelChanged(TableColorModelEvent e) {
102 Object[] listeners = this.listenerList.getListenerList();
103 for (int i = listeners.length - 2; i >= 0; i -= 2) {
104 if (listeners[i] == TableColorModelListener.class) {
105 ((TableColorModelListener) listeners[i + 1])
106 .tableColorModelChanged(e);
107 }
108 }
109 }
110
111 /***
112 * Enables to add listeners for the modifications of the color scheme.
113 *
114 * @param l
115 * the listener to add.
116 */
117 public void addTableColorModelListener(TableColorModelListener l) {
118 this.listenerList.add(TableColorModelListener.class, l);
119 }
120
121 /***
122 * Unregisters the listener for the modifications of the color model.
123 *
124 * @param l
125 * the listener to remove.
126 */
127 public void removeTableColorModelListener(TableColorModelListener l) {
128 this.listenerList.remove(TableColorModelListener.class, l);
129 }
130
131 /***
132 * Gives access to the foreground color of a cell.
133 *
134 * @param row
135 * the cell's row.
136 * @param column
137 * the cell's column.
138 * @param selected
139 * whether the cell is currently selected or not.
140 * @param renderer
141 * the renderer used to display the cell.
142 * @return the foreground color for the cell.
143 */
144 public Color getForegroundColor(int row, int column, boolean selected,
145 java.awt.Component renderer) {
146 Color result = null;
147 Color presentBGColor = renderer.getBackground();
148 Color presentFGColor = renderer.getForeground();
149 if (presentFGColor == null) {
150 presentFGColor = Color.black;
151 }
152 result = presentFGColor;
153 return ensureMinimumDistance(result, presentBGColor);
154 }
155
156 /***
157 * This method enables to generate a Color that may replace the parameter
158 * fgColor as a foreground Color. When the "distance" between the fgColor
159 * and the bgColor is lesser than MINIMUM_COLOR_DISTANCE, the returned
160 * color's components are: red = Math.max(0, Math.min(255, bgRed +
161 * MINIMUM_COLOR_DISTANCE * (fgRed - bgRed) / d)); green = Math.max(0,
162 * Math.min(255, bgGreen + MINIMUM_COLOR_DISTANCE * (fgGreen - bgGreen) /
163 * d)); blue = Math.max(0, Math.min(255, bgBlue + MINIMUM_COLOR_DISTANCE *
164 * (fgBlue - bgBlue) / d));
165 *
166 * @param fgColor
167 * the original foreground color.
168 * @param bgColor
169 * the original background color.
170 * @return the fgColor parameter or the aforementioned replacement color.
171 */
172 protected Color ensureMinimumDistance(Color fgColor, Color bgColor) {
173 Color result = fgColor;
174 int fgRed = fgColor.getRed();
175 int fgGreen = fgColor.getGreen();
176 int fgBlue = fgColor.getBlue();
177 int bgRed = bgColor.getRed();
178 int bgGreen = bgColor.getGreen();
179 int bgBlue = bgColor.getBlue();
180 int red, green, blue;
181 int d = getDistance(bgColor, fgColor);
182 if (d < MINIMUM_COLOR_DISTANCE) {
183 if (d == 0) {
184 d = 1;
185 }
186 red = Math.max(0, Math.min(255, bgRed + MINIMUM_COLOR_DISTANCE
187 * (fgRed - bgRed) / d));
188 green = Math.max(0, Math.min(255, bgGreen + MINIMUM_COLOR_DISTANCE
189 * (fgGreen - bgGreen) / d));
190 blue = Math.max(0, Math.min(255, bgBlue + MINIMUM_COLOR_DISTANCE
191 * (fgBlue - bgBlue) / d));
192 result = new Color(red, green, blue);
193 }
194 return result;
195 }
196
197 /***
198 * This method returns the "distance" between two colors. The distance is
199 * the usual euclidian distance in a three dimension space.
200 *
201 * @param colorOne
202 * the first color.
203 * @param colorTwo
204 * the second color.
205 * @return the euclidian distance between colorOne and colorTwo.
206 */
207 protected int getDistance(Color colorOne, Color colorTwo) {
208 int redDifference = colorTwo.getRed() - colorOne.getRed();
209 int greenDifference = colorTwo.getGreen() - colorOne.getGreen();
210 int blueDifference = colorTwo.getBlue() - colorOne.getBlue();
211 return (int) Math.sqrt((redDifference * redDifference)
212 + (greenDifference * greenDifference)
213 + (blueDifference * blueDifference));
214 }
215
216 /***
217 * This is a convenience method that enables to mix two colors. It may be
218 * used when a TableColorModel implementation needs to mix two layers of
219 * color.
220 *
221 * @param top
222 * the color that is on the top layer.
223 * @param bottom
224 * the color that is on the bottom layer.
225 * @return a mixed color between the two parameter colors. The color has the
226 * following components: red = 255 - Math.min(255, (6 * (255 -
227 * bottom.getRed()) + 4 * (255 - top.getRed())) / 10) green = 255 -
228 * Math.min(255, (6 * (255 - bottom.getGreen()) + 4 * (255 -
229 * top.getGreen())) / 10) blue = 255 - Math.min(255, (6 * (255 -
230 * bottom.getBlue()) + 4 * (255 - top.getBlue())) / 10)
231 */
232 protected Color mixColors(Color top, Color bottom) {
233 Color result = null;
234 if ((top != null) && (bottom != null)) {
235 int red = 255 - Math
236 .min(255, (6 * (255 - bottom.getRed()) + 4 * (255 - top
237 .getRed())) / 10);
238 int green = 255 - Math
239 .min(255, (6 * (255 - bottom.getGreen()) + 4 * (255 - top
240 .getGreen())) / 10);
241 int blue = 255 - Math
242 .min(255, (6 * (255 - bottom.getBlue()) + 4 * (255 - top
243 .getBlue())) / 10);
244 result = new Color(red, green, blue);
245 } else {
246 if (top != null) {
247 result = top;
248 }
249 if (bottom != null) {
250 result = bottom;
251 }
252 }
253 return result;
254 }
255
256
257 /***
258 * @see org.jcreme.swing.table.TableColorModel#getTableModel()
259 */
260 public TableModel getTableModel() {
261 return this.dataModel;
262 }
263 /***
264 * @see org.jcreme.swing.table.TableColorModel#setTableModel(javax.swing.table.TableModel)
265 */
266 public void setTableModel(TableModel model) {
267 this.dataModel = model;
268 }
269 }