/*
* This file is part of muCommander, http://www.mucommander.com
* Copyright (C) 2002-2016 Maxence Bernard
*
* muCommander is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* muCommander is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mucommander.ui.theme;
import javax.swing.*;
import java.awt.*;
import java.util.Hashtable;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Base class for all things Theme.
* <p>
* The role of <code>ThemeData</code> is twofold:<br/>
* - theme data storage.<br/>
* - default values retrievals and notification.<br/>
* </p>
* <p>
* In the current version, theme data is solely composed of assorted colors and fonts. <code>ThemeData</code>
* offers methods to {@link #setColor(int,Color) set}, {@link #getColor(int) retrieve}, {@link #isIdentical(ThemeData,boolean) compare}
* and {@link #cloneData() clone} these values.
* </p>
* <p>
* One of its major constraints is that it can <b>never</b> return <code>null</code> values for the items it contains. Whenever a specific
* value hasn't been set, <code>ThemeData</code> will seemlessly provide the rest of the world with default values retrieved from the current
* look&feel.
* </p>
* <p>
* This default values system means that theme items can change outside of anybody's control: Swing UI properties can be updated, the current
* look&feel can be modified... <code>ThemeData</code> will track this changes and make sure that the proper event are dispatched
* to listeners.
* </p>
* <p>
* In theory, classes that use the theme API should not need to worry about default value modifications. This is already managed internally, and
* if the change affects any of the themes being listened on, the event will be propagated to them. There might special cases where it's necessary,
* however, for which <code>ThemeData</code> provides a {@link #addDefaultValuesListener(ThemeListener) listening} mechanism.
* </p>
* @see Theme
* @see ThemeManager
* @see javax.swing.UIManager
* @author Nicolas Rinaudo
*/
public class ThemeData {
// - Dirty hack ----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
// This is an effort to make the ThemeData class a bit easier to maintain, but I'm the first
// to admit it's rather dirty.
//
// For optimization reasons, we're storing the fonts and colors in arrays, using their
// identifiers as indexes in the array. This, however, means that lots of bits of code
// must be updated whenever a font or color is added or removed. The probability of
// someone forgetting this is, well, 100%.
//
// For this reason, we've declared the number of font and colors as constants.
// People are still going to forget to update these constants, but at least it'll be
// a lot easier to fix.
/**
* Number of known fonts.
* <p>
* Since font identifiers are contiguous, it is possible to explore all fonts contained
* by an instance of theme data by looping from 0 to this value.
* </p>
*/
public static final int FONT_COUNT = 8;
/**
* Number of known colors.
* <p>
* Since color identifiers are contiguous, it is possible to explore all colors contained
* by an instance of theme data by looping from 0 to this color.
* </p>
*/
public static final int COLOR_COUNT = 68;
// - Font definitions ----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Font used in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> font.
* </p>
*/
public static final int FILE_TABLE_FONT = 0;
/**
* Font used to display shell output.
* <p>
* This defaults to the current <code>JTextArea</code> font.
* </p>
*/
public static final int SHELL_FONT = 1;
/**
* Font used in the file editor and viewer.
* <p>
* This defaults to the current <code>JTable</code> font.
* </p>
*/
public static final int EDITOR_FONT = 2;
/**
* Font used in the location bar.
* <p>
* This defaults to the current <code>JTextField</code> font.
* </p>
*/
public static final int LOCATION_BAR_FONT = 3;
/**
* Font used in the shell history widget.
* <p>
* This defaults to the current <code>JTextField</code> font.
* </p>
*/
public static final int SHELL_HISTORY_FONT = 4;
/**
* Font used in the status bar.
* <p>
* This defaults to the current <code>JLabel</code> font.
* </p>
*/
public static final int STATUS_BAR_FONT = 5;
/**
* Font used in the quick list header.
* <p>
* This defaults to a similar font of the current <code>JTable</code> font, but a little bigger.
* </p>
*/
public static final int QUICK_LIST_HEADER_FONT = 6;
/**
* Font used in the quick list item.
* <p>
* This defaults to the current <code>JTable</code> font.
* </p>
*/
public static final int QUICK_LIST_ITEM_FONT = 7;
// - Color definitions ---------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Color used to paint the folder panels' borders.
* <p>
* This defaults to <code>Color.GRAY</code>.
* </p>
*/
public static final int FILE_TABLE_BORDER_COLOR = 0;
/**
* Color used to paint the folder panels' borders when it doesn't have the focus.
* <p>
* This defaults to <code>Color.GRAY</code>.
* </p>
*/
public static final int FILE_TABLE_INACTIVE_BORDER_COLOR = 56;
/**
* Color used to paint the folder panel's background color.
* <p>
* This defaults to the current <code>JTable</code> background color.
* </p>
*/
public static final int FILE_TABLE_BACKGROUND_COLOR = 1;
/**
* Color used to paint the folder panel's alternate background color.
* <p>
* This defaults to the current <code>JTable</code> background color.
* </p>
*/
public static final int FILE_TABLE_ALTERNATE_BACKGROUND_COLOR = 2;
/**
* Color used to paint the folder panel's background color when it doesn't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #FILE_TABLE_BACKGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int FILE_TABLE_INACTIVE_BACKGROUND_COLOR = 3;
/**
* Color used to paint the folder panel's alternate background color when inactive.
* <p>
* This defaults to the current <code>JTable</code> background color.
* </p>
*/
public static final int FILE_TABLE_INACTIVE_ALTERNATE_BACKGROUND_COLOR = 4;
/**
* Color used to paint the file table's background color when it's part of an unmatched file.
*/
public static final int FILE_TABLE_UNMATCHED_BACKGROUND_COLOR = 5;
/**
* Color used to paint the file table's foreground color when it's part of an unmatched file.
*/
public static final int FILE_TABLE_UNMATCHED_FOREGROUND_COLOR = 6;
/**
* Color used to paint the file table's background color when in a selected row.
*/
public static final int FILE_TABLE_SELECTED_BACKGROUND_COLOR = 7;
/**
* Color used to paint the gradient of the file table's selection.
*/
public static final int FILE_TABLE_SELECTED_SECONDARY_BACKGROUND_COLOR = 59;
/**
* Color used to paint the gradient of the file table's selection when inactive.
*/
public static final int FILE_TABLE_INACTIVE_SELECTED_SECONDARY_BACKGROUND_COLOR = 60;
/**
* Colors used to pain the file table's background color when in an inactive selected row.
*/
public static final int FILE_TABLE_INACTIVE_SELECTED_BACKGROUND_COLOR = 8;
/**
* Color used to paint hidden files text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> foreground color.
* </p>
*/
public static final int HIDDEN_FILE_FOREGROUND_COLOR = 9;
/**
* Color used to paint hidden files text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #HIDDEN_FILE_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR = 10;
/**
* Color used to paint selected hidden files text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> selection foreground color.
* </p>
*/
public static final int HIDDEN_FILE_SELECTED_FOREGROUND_COLOR = 11;
/**
* Color used to paint selected hidden files text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #HIDDEN_FILE_SELECTED_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR = 12;
/**
* Color used to paint folders text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> foreground color.
* </p>
*/
public static final int FOLDER_FOREGROUND_COLOR = 13;
/**
* Color used to paint folders text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #FOLDER_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int FOLDER_INACTIVE_FOREGROUND_COLOR = 14;
/**
* Color used to paint selected folders text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> selection foreground color.
* </p>
*/
public static final int FOLDER_SELECTED_FOREGROUND_COLOR = 15;
/**
* Color used to paint selected folders text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #FOLDER_SELECTED_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int FOLDER_INACTIVE_SELECTED_FOREGROUND_COLOR = 16;
/**
* Color used to paint archives text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> foreground color.
* </p>
*/
public static final int ARCHIVE_FOREGROUND_COLOR = 17;
/**
* Color used to paint archives text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #ARCHIVE_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int ARCHIVE_INACTIVE_FOREGROUND_COLOR = 18;
/**
* Color used to paint selected archives text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> selection foreground color.
* </p>
*/
public static final int ARCHIVE_SELECTED_FOREGROUND_COLOR = 19;
/**
* Color used to paint selected archives text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #ARCHIVE_SELECTED_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR = 20;
/**
* Color used to paint symlinks text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> foreground color.
* </p>
*/
public static final int SYMLINK_FOREGROUND_COLOR = 21;
/**
* Color used to paint symlinks text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #SYMLINK_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int SYMLINK_INACTIVE_FOREGROUND_COLOR = 22;
/**
* Color used to paint selected symlinks text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> selection foreground color.
* </p>
*/
public static final int SYMLINK_SELECTED_FOREGROUND_COLOR = 23;
/**
* Color used to paint selected symlinks text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #SYMLINK_SELECTED_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR = 24;
/**
* Color used to paint marked files text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> foreground color.
* </p>
*/
public static final int MARKED_FOREGROUND_COLOR = 25;
/**
* Color used to paint marked files text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #MARKED_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int MARKED_INACTIVE_FOREGROUND_COLOR = 26;
/**
* Color used to paint selected marked files text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> selection foreground color.
* </p>
*/
public static final int MARKED_SELECTED_FOREGROUND_COLOR = 27;
/**
* Color used to paint selected marked files text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #MARKED_SELECTED_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int MARKED_INACTIVE_SELECTED_FOREGROUND_COLOR = 28;
/**
* Color used to paint plain files text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> foreground color.
* </p>
*/
public static final int FILE_FOREGROUND_COLOR = 29;
/**
* Color used to paint plain files text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #FILE_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int FILE_INACTIVE_FOREGROUND_COLOR = 30;
/**
* Color used to paint selected plain files text in the folder panels.
* <p>
* This defaults to the current <code>JTable</code> selection foreground color.
* </p>
*/
public static final int FILE_SELECTED_FOREGROUND_COLOR = 31;
/**
* Color used to paint selected plain files text in the folder panels when they don't have the focus.
* <p>
* This behaves in exactly the same fashion as {@link #FILE_SELECTED_FOREGROUND_COLOR}, and defaults
* to the same value.
* </p>
*/
public static final int FILE_INACTIVE_SELECTED_FOREGROUND_COLOR = 32;
/**
* Color used to paint shell commands output.
* <p>
* This defaults to the current <code>JTextArea</code> foreground color.
* </p>
*/
public static final int SHELL_FOREGROUND_COLOR = 33;
/**
* Color used to paint the background of shell commands output.
* <p>
* This defaults to the current <code>JTextArea</code> background color.
* </p>
*/
public static final int SHELL_BACKGROUND_COLOR = 34;
/**
* Color used to paint shell commands output when selected.
* <p>
* This defaults to the current <code>JTextArea</code> selection foreground color.
* </p>
*/
public static final int SHELL_SELECTED_FOREGROUND_COLOR = 35;
/**
* Color used to paint the background of shell commands output when selected.
* <p>
* This defaults to the current <code>JTextArea</code> selection background color.
* </p>
*/
public static final int SHELL_SELECTED_BACKGROUND_COLOR = 36;
/**
* Color used to paint the shell history's text.
* <p>
* This defaults to the current <code>JTextField</code> foreground color.
* </p>
*/
public static final int SHELL_HISTORY_FOREGROUND_COLOR = 37;
/**
* Color used to paint the shell history's background.
* <p>
* This defaults to the current <code>JTextField</code> background color.
* </p>
*/
public static final int SHELL_HISTORY_BACKGROUND_COLOR = 38;
/**
* Color used to paint the shell history's text when selected.
* <p>
* This defaults to the current <code>JTextField</code> selection foreground color.
* </p>
*/
public static final int SHELL_HISTORY_SELECTED_FOREGROUND_COLOR = 39;
/**
* Color used to paint the shell history's background when selected.
* <p>
* This defaults to the current <code>JTextField</code> selection background color.
* </p>
*/
public static final int SHELL_HISTORY_SELECTED_BACKGROUND_COLOR = 40;
/**
* Color used to paint the file editor / viewer's text.
* <p>
* This defaults to the current <code>JTextArea</code> foreground color.
* </p>
*/
public static final int EDITOR_FOREGROUND_COLOR = 41;
/**
* Color used to paint the file editor / viewer's background.
* <p>
* This defaults to the current <code>JTextArea</code> background color.
* </p>
*/
public static final int EDITOR_BACKGROUND_COLOR = 42;
/**
* Color used to paint the file editor / viewer's foreground when selected.
* <p>
* This defaults to the current <code>JTextArea</code> selection foreground color.
* </p>
*/
public static final int EDITOR_SELECTED_FOREGROUND_COLOR = 43;
/**
* Color used to paint the file editor / viewer's background when selected.
* <p>
* This defaults to the current <code>JTextArea</code> selection background color.
* </p>
*/
public static final int EDITOR_SELECTED_BACKGROUND_COLOR = 44;
/**
* Color used to paint the location's bar text.
* <p>
* This defaults to the current <code>JTextField</code> foreground color.
* </p>
*/
public static final int LOCATION_BAR_FOREGROUND_COLOR = 45;
/**
* Color used to paint the location's bar background.
* <p>
* This defaults to the current <code>JTextField</code> background color.
* </p>
*/
public static final int LOCATION_BAR_BACKGROUND_COLOR = 46;
/**
* Color used to paint the location's bar text when selected.
* <p>
* This defaults to the current <code>JTextField</code> selection foreground color.
* </p>
*/
public static final int LOCATION_BAR_SELECTED_FOREGROUND_COLOR = 47;
/**
* Color used to paint the location's bar background when selected.
* <p>
* This defaults to the current <code>JTextField</code> selection background color.
* </p>
*/
public static final int LOCATION_BAR_SELECTED_BACKGROUND_COLOR = 48;
/**
* Color used to paint the location's bar background when used as a progress bar.
* <p>
* Note that this color is painted over the location's bar background and foreground. In order
* for anything to be visible under it, it needs to have an alpha transparency component.
* </p>
* <p>
* This defaults to the current <code>JTextField</code> selection background color, with an
* alpha transparency value of 64.
* </p>
*/
public static final int LOCATION_BAR_PROGRESS_COLOR = 49;
/**
* Color used to paint the status bar's text.
* <p>
* This defaults to the current <code>JLabel</code> foreground color.
* </p>
*/
public static final int STATUS_BAR_FOREGROUND_COLOR = 50;
/**
* Color used to paint the status bar's background
* <p>
* This defaults to the current <code>JLabel</code> background color.
* </p>
*/
public static final int STATUS_BAR_BACKGROUND_COLOR = 51;
/**
* Color used to paint the status bar's border.
* <p>
* This defaults to <code>Color.GRAY</code>.
* </p>
*/
public static final int STATUS_BAR_BORDER_COLOR = 52;
/**
* Color used to paint the status bar's drive usage color when there's plenty of space left.
* <p>
* This defaults to <code>0x70EC2B</code>.
* </p>
*/
public static final int STATUS_BAR_OK_COLOR = 53;
/**
* Color used to paint the status bar's drive usage color when there's an average amount of space left.
* <p>
* This defaults to <code>0xFF7F00</code>.
* </p>
*/
public static final int STATUS_BAR_WARNING_COLOR = 54;
/**
* Color used to paint the status bar's drive usage color when there's dangerously little space left.
* <p>
* This defaults to <code>Color.RED</code>.
* </p>
*/
public static final int STATUS_BAR_CRITICAL_COLOR = 55;
/**
* Color used to paint the outline of selected files.
*/
public static final int FILE_TABLE_SELECTED_OUTLINE_COLOR = 57;
/**
* Color used to paint the outline of selected files in an inactive table.
*/
public static final int FILE_TABLE_INACTIVE_SELECTED_OUTLINE_COLOR = 58;
/**
* Color used to paint the main background of a quick list header.
*/
public static final int QUICK_LIST_HEADER_BACKGROUND_COLOR = 61;
/**
* Color used to paint the secondary background of a quick list header.
*/
public static final int QUICK_LIST_HEADER_SECONDARY_BACKGROUND_COLOR = 62;
/**
* Color used to paint the text of a quick list header.
*/
public static final int QUICK_LIST_HEADER_FOREGROUND_COLOR = 63;
/**
* Color used to paint the background of a quick list item.
*/
public static final int QUICK_LIST_ITEM_BACKGROUND_COLOR = 64;
/**
* Color used to paint the text of a quick list item.
*/
public static final int QUICK_LIST_ITEM_FOREGROUND_COLOR = 65;
/**
* Color used to paint the background of a selected quick list item.
*/
public static final int QUICK_LIST_SELECTED_ITEM_BACKGROUND_COLOR = 66;
/**
* Color used to paint the text of a selected quick list item.
*/
public static final int QUICK_LIST_SELECTED_ITEM_FOREGROUND_COLOR = 67;
// - Default fonts -------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
// The following fields are look&feel dependant values for the fonts that are used by
// themes. We need to monitor them, as they are prone to change through UIManager.
// - Default identifiers -------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
public static final String DEFAULT_TEXT_AREA_FOREGROUND = "TextArea.foreground";
public static final String DEFAULT_TEXT_AREA_BACKGROUND = "TextArea.background";
public static final String DEFAULT_TEXT_AREA_SELECTION_FOREGROUND = "TextArea.selectionForeground";
public static final String DEFAULT_TEXT_AREA_SELECTION_BACKGROUND = "TextArea.selectionBackground";
public static final String DEFAULT_TEXT_FIELD_FOREGROUND = "TextField.foreground";
public static final String DEFAULT_TEXT_FIELD_BACKGROUND = "TextField.background";
public static final String DEFAULT_TEXT_FIELD_SELECTION_FOREGROUND = "TextField.selectionForeground";
public static final String DEFAULT_TEXT_FIELD_SELECTION_BACKGROUND = "TextField.selectionBackground";
public static final String DEFAULT_TEXT_FIELD_PROGRESS_BACKGROUND = "TextField.progress";
public static final String DEFAULT_TABLE_FOREGROUND = "Table.foreground";
public static final String DEFAULT_TABLE_BACKGROUND = "Table.background";
public static final String DEFAULT_TABLE_SELECTION_FOREGROUND = "Table.selectionForeground";
public static final String DEFAULT_TABLE_SELECTION_BACKGROUND = "Table.selectionBackground";
public static final String DEFAULT_TABLE_UNMATCHED_FOREGROUND = "Table.unmatchedForeground";
public static final String DEFAULT_TABLE_UNMATCHED_BACKGROUND = "Table.unmatchedBackground";
public static final String DEFAULT_MENU_HEADER_FOREGROUND = "MenuHeader.foreground";
public static final String DEFAULT_MENU_HEADER_BACKGROUND = "MenuHeader.background";
public static final String DEFAULT_TEXT_AREA_FONT = "TextArea.font";
public static final String DEFAULT_TEXT_FIELD_FONT = "TextField.font";
public static final String DEFAULT_LABEL_FONT = "Label.font";
public static final String DEFAULT_TABLE_FONT = "Table.font";
public static final String DEFAULT_MENU_HEADER_FONT = "MenuHeader.font";
// - Listeners -----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/** Listeners on the default font and colors. */
private static WeakHashMap<ThemeListener, ?> listeners = new WeakHashMap<ThemeListener, Object>();
// - Registered colors & fonts -------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/** All registered colors. */
private static final Map<Integer, DefaultColor> COLORS;
/** All registered default colors. */
private static final Map<String, DefaultColor> DEFAULT_COLORS;
/** All registered fonts. */
private static final Map<Integer, DefaultFont> FONTS;
/** All registered default fonts. */
private static final Map<String, DefaultFont> DEFAULT_FONTS;
// - Instance variables --------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/** All the colors contained by the theme. */
private Color[] colors;
/** All the fonts contained by the theme. */
private Font[] fonts;
public static void registerDefaultColor(String name, DefaultColor color) {
DEFAULT_COLORS.put(name, color);
}
public static void registerDefaultFont(String name, DefaultFont font) {
DEFAULT_FONTS.put(name, font);
}
public static void registerColor(int id, String defaultColor) {
DefaultColor color;
if((color = DEFAULT_COLORS.get(defaultColor)) == null)
throw new IllegalArgumentException("Not a registered default color: " + defaultColor);
registerColor(id, color);
}
public static void registerFont(int id, String defaultFont) {
DefaultFont font;
if((font = DEFAULT_FONTS.get(defaultFont)) == null)
throw new IllegalArgumentException("Not a registered default font: " + defaultFont);
registerFont(id, font);
}
public static void registerColor(int id, Color color) {
registerColor(id, new FixedDefaultColor(color));
}
public static void registerFont(int id, Font font) {
registerFont(id, new FixedDefaultFont(font));
}
public static void registerColor(int id, int defaultId) {
registerColor(id, new LinkedDefaultColor(defaultId));
}
public static void registerFont(int id, int defaultId) {
registerFont(id, new LinkedDefaultFont(defaultId));
}
public static void registerColor(int id, DefaultColor color) {
Integer colorId;
colorId = id;
COLORS.put(colorId, color);
color.link(colorId);
}
public static void registerFont(int id, DefaultFont font) {
Integer fontId;
fontId = id;
FONTS.put(fontId, font);
font.link(fontId);
}
static {
ComponentMapper mapper;
COLORS = new Hashtable<Integer, DefaultColor>();
DEFAULT_COLORS = new Hashtable<String, DefaultColor>();
FONTS = new Hashtable<Integer, DefaultFont>();
DEFAULT_FONTS = new Hashtable<String, DefaultFont>();
// - Default values registering --------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------------------
mapper = new ComponentMapper() {
@Override
public JComponent getComponent() {return new JTextArea();}};
registerDefaultFont(DEFAULT_TEXT_AREA_FONT,new SystemDefaultFont("TextArea.font", mapper));
registerDefaultColor(DEFAULT_TEXT_AREA_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.FOREGROUND, "TextArea.foreground", mapper));
registerDefaultColor(DEFAULT_TEXT_AREA_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.BACKGROUND, "TextArea.background", mapper));
registerDefaultColor(DEFAULT_TEXT_AREA_SELECTION_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.SELECTION_FOREGROUND, "TextArea.selectionForeground", mapper));
registerDefaultColor(DEFAULT_TEXT_AREA_SELECTION_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.SELECTION_BACKGROUND, "TextArea.selectionBackground", mapper));
// Register TextField related default values.
mapper = new ComponentMapper() {
@Override
public JComponent getComponent() {return new JTextField();}};
registerDefaultFont(DEFAULT_TEXT_FIELD_FONT, new SystemDefaultFont("TextField.font", mapper));
registerDefaultColor(DEFAULT_TEXT_FIELD_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.FOREGROUND, "TextField.foreground", mapper));
registerDefaultColor(DEFAULT_TEXT_FIELD_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.BACKGROUND, "TextField.background", mapper));
registerDefaultColor(DEFAULT_TEXT_FIELD_SELECTION_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.SELECTION_FOREGROUND, "TextField.selectionForeground", mapper));
registerDefaultColor(DEFAULT_TEXT_FIELD_SELECTION_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.SELECTION_BACKGROUND, "TextField.selectionBackground", mapper));
registerDefaultColor(DEFAULT_TEXT_FIELD_PROGRESS_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.SELECTION_BACKGROUND, "TextField.selectionBackground", mapper) {
@Override
public Color getColor(ThemeData data) {
Color color;
color = super.getColor(data);
return new Color(color.getRed(), color.getGreen(), color.getBlue(), 64);
}
});
// Register Table related default values.
mapper = new ComponentMapper() {
@Override
public JComponent getComponent() {return new JTable();}};
registerDefaultFont(DEFAULT_TABLE_FONT, new SystemDefaultFont("Table.font", mapper));
registerDefaultColor(DEFAULT_TABLE_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.FOREGROUND, "Table.foreground", mapper));
registerDefaultColor(DEFAULT_TABLE_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.BACKGROUND, "Table.background", mapper));
registerDefaultColor(DEFAULT_TABLE_SELECTION_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.SELECTION_FOREGROUND, "Table.selectionForeground", mapper));
registerDefaultColor(DEFAULT_TABLE_SELECTION_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.SELECTION_BACKGROUND, "Table.selectionBackground", mapper));
registerDefaultColor(DEFAULT_TABLE_UNMATCHED_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.FOREGROUND, "Table.foreground", mapper) {
@Override
public Color getColor(ThemeData data) {
return super.getColor(data).darker();
}
});
registerDefaultColor(DEFAULT_TABLE_UNMATCHED_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.BACKGROUND, "Table.background", mapper) {
@Override
public Color getColor(ThemeData data) {
return super.getColor(data).darker();
}
});
// Menu header related default values.
mapper = new ComponentMapper() {
@Override
public JComponent getComponent() {return new JInternalFrame();}};
registerDefaultFont(DEFAULT_MENU_HEADER_FONT, new SystemDefaultFont("InternalFrame.font", mapper));
registerDefaultColor(DEFAULT_MENU_HEADER_BACKGROUND,
new SystemDefaultColor(SystemDefaultColor.BACKGROUND, "InternalFrame.activeTitleBackground", mapper));
registerDefaultColor(DEFAULT_MENU_HEADER_FOREGROUND,
new SystemDefaultColor(SystemDefaultColor.FOREGROUND, "InternalFrame.activeTitleForeground", mapper));
// Label related default values.
mapper = new ComponentMapper() {
@Override
public JComponent getComponent() {return new JLabel();}};
registerDefaultFont(DEFAULT_LABEL_FONT, new SystemDefaultFont("Label.font", mapper));
// - Default values linking ------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------------------
// QuickList default values.
registerFont(QUICK_LIST_ITEM_FONT, DEFAULT_TABLE_FONT);
registerFont(QUICK_LIST_HEADER_FONT, DEFAULT_MENU_HEADER_FONT);
registerColor(QUICK_LIST_HEADER_SECONDARY_BACKGROUND_COLOR, DEFAULT_MENU_HEADER_BACKGROUND);
registerColor(QUICK_LIST_HEADER_BACKGROUND_COLOR, DEFAULT_MENU_HEADER_BACKGROUND);
registerColor(QUICK_LIST_HEADER_FOREGROUND_COLOR, DEFAULT_MENU_HEADER_FOREGROUND);
registerColor(QUICK_LIST_ITEM_BACKGROUND_COLOR, FILE_TABLE_BACKGROUND_COLOR);
registerColor(QUICK_LIST_ITEM_FOREGROUND_COLOR, FILE_FOREGROUND_COLOR);
registerColor(QUICK_LIST_SELECTED_ITEM_BACKGROUND_COLOR, FILE_TABLE_SELECTED_BACKGROUND_COLOR);
registerColor(QUICK_LIST_SELECTED_ITEM_FOREGROUND_COLOR, FILE_SELECTED_FOREGROUND_COLOR);
// File default values.
registerColor(HIDDEN_FILE_FOREGROUND_COLOR, Color.GRAY);
registerColor(FOLDER_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(ARCHIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(SYMLINK_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(FILE_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR, Color.GRAY);
registerColor(FOLDER_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(ARCHIVE_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(SYMLINK_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(FILE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND);
registerColor(HIDDEN_FILE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(FOLDER_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(ARCHIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(SYMLINK_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(FOLDER_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
registerColor(FILE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND);
// FileTable default values.
registerFont(FILE_TABLE_FONT, DEFAULT_TABLE_FONT);
registerColor(FILE_TABLE_BACKGROUND_COLOR, DEFAULT_TABLE_BACKGROUND);
registerColor(FILE_TABLE_INACTIVE_BACKGROUND_COLOR, DEFAULT_TABLE_BACKGROUND);
registerColor(FILE_TABLE_ALTERNATE_BACKGROUND_COLOR, DEFAULT_TABLE_BACKGROUND);
registerColor(FILE_TABLE_INACTIVE_ALTERNATE_BACKGROUND_COLOR, DEFAULT_TABLE_BACKGROUND);
registerColor(FILE_TABLE_SELECTED_BACKGROUND_COLOR, DEFAULT_TABLE_SELECTION_BACKGROUND);
registerColor(FILE_TABLE_INACTIVE_SELECTED_BACKGROUND_COLOR, DEFAULT_TABLE_SELECTION_BACKGROUND);
registerColor(FILE_TABLE_UNMATCHED_FOREGROUND_COLOR, DEFAULT_TABLE_UNMATCHED_FOREGROUND);
registerColor(FILE_TABLE_UNMATCHED_BACKGROUND_COLOR, DEFAULT_TABLE_UNMATCHED_BACKGROUND);
registerColor(STATUS_BAR_BACKGROUND_COLOR, new Color(0xD5D5D5));
registerColor(MARKED_FOREGROUND_COLOR, Color.RED);
registerColor(MARKED_INACTIVE_FOREGROUND_COLOR, Color.RED);
registerColor(MARKED_SELECTED_FOREGROUND_COLOR, Color.RED);
registerColor(MARKED_INACTIVE_SELECTED_FOREGROUND_COLOR, Color.RED);
registerColor(FILE_TABLE_BORDER_COLOR, Color.GRAY);
registerColor(FILE_TABLE_INACTIVE_BORDER_COLOR, Color.GRAY);
registerColor(FILE_TABLE_SELECTED_SECONDARY_BACKGROUND_COLOR, FILE_TABLE_SELECTED_BACKGROUND_COLOR);
registerColor(FILE_TABLE_SELECTED_OUTLINE_COLOR, FILE_TABLE_SELECTED_BACKGROUND_COLOR);
registerColor(FILE_TABLE_INACTIVE_SELECTED_SECONDARY_BACKGROUND_COLOR, FILE_TABLE_INACTIVE_SELECTED_BACKGROUND_COLOR);
registerColor(FILE_TABLE_INACTIVE_SELECTED_OUTLINE_COLOR, FILE_TABLE_INACTIVE_SELECTED_BACKGROUND_COLOR);
// Shell default values.
registerFont(SHELL_FONT, DEFAULT_TEXT_AREA_FONT);
registerFont(SHELL_HISTORY_FONT, DEFAULT_TEXT_FIELD_FONT);
registerColor(SHELL_FOREGROUND_COLOR, DEFAULT_TEXT_AREA_FOREGROUND);
registerColor(SHELL_BACKGROUND_COLOR, DEFAULT_TEXT_AREA_BACKGROUND);
registerColor(SHELL_SELECTED_FOREGROUND_COLOR, DEFAULT_TEXT_AREA_SELECTION_FOREGROUND);
registerColor(SHELL_SELECTED_BACKGROUND_COLOR, DEFAULT_TEXT_AREA_SELECTION_BACKGROUND);
registerColor(SHELL_HISTORY_FOREGROUND_COLOR, DEFAULT_TEXT_FIELD_FOREGROUND);
registerColor(SHELL_HISTORY_BACKGROUND_COLOR, DEFAULT_TEXT_FIELD_BACKGROUND);
registerColor(SHELL_HISTORY_SELECTED_FOREGROUND_COLOR, DEFAULT_TEXT_FIELD_SELECTION_FOREGROUND);
registerColor(SHELL_HISTORY_SELECTED_BACKGROUND_COLOR, DEFAULT_TEXT_FIELD_SELECTION_BACKGROUND);
// Editor default values.
registerFont(EDITOR_FONT, DEFAULT_TEXT_AREA_FONT);
registerColor(EDITOR_FOREGROUND_COLOR, DEFAULT_TEXT_AREA_FOREGROUND);
registerColor(EDITOR_BACKGROUND_COLOR, DEFAULT_TEXT_AREA_BACKGROUND);
registerColor(EDITOR_SELECTED_FOREGROUND_COLOR, DEFAULT_TEXT_AREA_SELECTION_FOREGROUND);
registerColor(EDITOR_SELECTED_BACKGROUND_COLOR, DEFAULT_TEXT_AREA_SELECTION_BACKGROUND);
// Location default values.
registerFont(LOCATION_BAR_FONT, DEFAULT_TEXT_FIELD_FONT);
registerColor(LOCATION_BAR_FOREGROUND_COLOR, DEFAULT_TEXT_FIELD_FOREGROUND);
registerColor(LOCATION_BAR_BACKGROUND_COLOR, DEFAULT_TEXT_FIELD_BACKGROUND);
registerColor(LOCATION_BAR_SELECTED_FOREGROUND_COLOR, DEFAULT_TEXT_FIELD_SELECTION_FOREGROUND);
registerColor(LOCATION_BAR_SELECTED_BACKGROUND_COLOR, DEFAULT_TEXT_FIELD_SELECTION_BACKGROUND);
registerColor(LOCATION_BAR_PROGRESS_COLOR, DEFAULT_TEXT_FIELD_PROGRESS_BACKGROUND);
// Status bar default values.
registerFont(STATUS_BAR_FONT, DEFAULT_LABEL_FONT);
registerColor(STATUS_BAR_FOREGROUND_COLOR, DEFAULT_TEXT_FIELD_FOREGROUND);
registerColor(STATUS_BAR_CRITICAL_COLOR, Color.RED);
registerColor(STATUS_BAR_BORDER_COLOR, Color.GRAY);
registerColor(STATUS_BAR_BACKGROUND_COLOR, new Color(0xD5D5D5));
registerColor(STATUS_BAR_OK_COLOR, new Color(0x70EC2B));
registerColor(STATUS_BAR_WARNING_COLOR, new Color(0xFF7F00));
}
/**
* Creates an empty set of theme data.
* <p>
* <code>ThemeData</code> instances created that way will return default values for every
* single one of their items.
* </p>
* @see #cloneData()
*/
public ThemeData() {
colors = new Color[COLOR_COUNT];
fonts = new Font[FONT_COUNT];
}
/**
* Creates a new set of theme data.
* <p>
* The content of <code>from</code> will be copied in the new theme data. Note that
* since we're copying the arrays themselves, rather than creating new ones and copying
* each color and font individually, <code>from</code> will be unreliable at the end of this
* call.
* </p>
* <p>
* This constructor is only meant for optimisation purposes. When transforming
* theme data in a proper theme, using this constructor allows us to not duplicate
* all the fonts and color. It's a risky constructor to use, however, and should not be exposed
* outside of the scope of the package.
* </p>
* @param from theme data from which to import values.
*/
ThemeData(ThemeData from) {
this();
fonts = from.fonts;
colors = from.colors;
}
// - Data import / export ------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Clones the current theme data.
* <p>
* This method allows callers to decide whether they want to <i>freeze</i> default values or
* not. Freezing a value means that it will be considered to have been set to the default value,
* and will not be updated when this default value changes.
* </p>
* @param freezeDefaults whether or not to freeze the data's default values.
* @return a clone of the current theme data.
* @see #cloneData()
*/
public ThemeData cloneData(boolean freezeDefaults) {
ThemeData data; // New data.
int i; // Used to browse the fonts and colors.
data = new ThemeData();
// Clones the theme's colors.
for(i = 0; i < COLOR_COUNT; i++)
data.colors[i] = freezeDefaults ? getColor(i) : colors[i];
// Clones the theme's fonts.
for(i = 0; i < FONT_COUNT; i++)
data.fonts[i] = freezeDefaults ? getFont(i) : fonts[i];
return data;
}
/**
* Clones the theme data without freezing default values.
* <p>
* This is a convenience method, and is exactly equivalent to calling <code>{@link #cloneData(boolean) cloneData(false)}</code>.
* </p>
* @return a clone of the current theme data.
*/
public ThemeData cloneData() {return cloneData(false);}
/**
* Imports the specified data in the current one.
* <p>
* This method can be dangerous in that it overwrites every single value
* of the current data without hope of retrieval. Moreoever, if something were to
* go wrong during the operation and an exception was raised, the current data would
* find itself in an invalid state, where some of its values would have been updated but
* not all of them. It is up to callers to deal with these issues.
* </p>
* <p>
* Values overwritting is done through the use of the current instance's {@link #setColor(int,Color)}
* and {@link #setFont(int,Font)} methods. This allows subclasses to plug their own code here. A good
* example of that is {@link Theme}, which will automatically trigger font and color events when
* importing data.
* </p>
* @param data data to import.
*/
public void importData(ThemeData data) {
int i;
// Imports the theme's colors.
for(i = 0; i < COLOR_COUNT; i++)
setColor(i, data.colors[i]);
// Imports the theme's fonts.
for(i = 0; i < FONT_COUNT; i++)
setFont(i, data.fonts[i]);
}
// - Items setting -------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Sets the specified color to the specified value.
* <p>
* Use a value of <code>null</code> to restore the color to it's default value.
* </p>
* <p>
* This method will return <code>false</code> if it didn't actually change the theme data.
* This is checked through the use of <code>{@link #isColorDifferent(int,Color) isColorDifferent(}id,color)</code>.
* </p>
* <p>
* Note that even if the color is found to be identical, the previous value will be overwritten -
* this is a design choice, meant for these cases where developers need to work with home-made
* subclasses of <code>Color</code>.
* </p>
* @param id identifier of the color to set.
* @param color value to which the color should be set.
* @return <code>true</code> if the call actually changed the data, <code>false</code> otherwise.
*/
public synchronized boolean setColor(int id, Color color) {
boolean buffer; // Used to store the result of isColorDifferent.
buffer = isColorDifferent(id, color);
colors[id] = color;
switch(id) {
case FILE_TABLE_SELECTED_SECONDARY_BACKGROUND_COLOR:
case FILE_TABLE_SELECTED_OUTLINE_COLOR:
case FILE_TABLE_INACTIVE_SELECTED_SECONDARY_BACKGROUND_COLOR:
case FILE_TABLE_INACTIVE_SELECTED_OUTLINE_COLOR:
triggerColorEvent(id, color);
}
return buffer;
}
/**
* Sets the specified font to the specified value.
* <p>
* Use a value of <code>null</code> to restore the font to it's default value.
* </p>
* <p>
* This method will return <code>false</code> if it didn't actually change the theme data.
* This is checked through the use of <code>{@link #isFontDifferent(int,Font) isFontDifferent(}id, font)</code>.
* </p>
* <p>
* Note that even if the font is found to be identical, the previous value will be overwritten -
* this is a design choice, meant for these cases where developers need to work with home-made
* subclasses of <code>Font</code>.
* </p>
* @param id identifier of the font to set.
* @param font value to which the font should be set.
* @return <code>true</code> if the call actually changed the data, <code>false</code> otherwise.
*/
public synchronized boolean setFont(int id, Font font) {
boolean buffer; // Used to store the result of isFontDifferent.
buffer = isFontDifferent(id, font);
fonts[id] = font;
return buffer;
}
// - Items retrieval -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Returns the requested color.
* <p>
* If the requested color wasn't set, its default value will be returned.
* </p>
* @param id identifier of the color to retrieve.
* @return the requested color, or its default value if not set.
* @see #getDefaultColor(int,ThemeData)
* @see #isColorSet(int)
*/
public synchronized Color getColor(int id) {
checkColorIdentifier(id);
return (colors[id] == null) ? getDefaultColor(id, this) : colors[id];
}
/**
* Returns the requested font.
* <p>
* If the requested font wasn't set, its default value will be returned.
* </p>
* @param id identifier of the font to retrieve.
* @return the requested font, or its default value if not set.
* @see #getDefaultFont(int, ThemeData)
* @see #isFontSet(int)
*/
public synchronized Font getFont(int id) {
checkFontIdentifier(id);
return (fonts[id] == null) ? getDefaultFont(id, this) : fonts[id];
}
/**
* Returns <code>true</code> if the specified color is set.
* @param id identifier of the color to check for.
* @return <code>true</code> if the specified color is set, <code>false</code> otherwise.
* @see #getDefaultColor(int,ThemeData)
*/
public boolean isColorSet(int id) {return colors[id] != null;}
/**
* Returns <code>true</code> if the specified font is set.
* @param id identifier of the font to check for.
* @return <code>true</code> if the specified font is set, <code>false</code> otherwise.
* @see #getDefaultFont(int, ThemeData)
*/
public boolean isFontSet(int id) {return fonts[id] != null;}
/**
* Returns the default value for the specified color.
* <p>
* Default values are look&feel dependant, and are subject to change during the application's
* life time.<br/>
* Classes that need to monitor such changes can register themselves using {@link #addDefaultValuesListener(ThemeListener)}.
* </p>
* @param id identifier of the color whose default value should be retrieved.
* @param data theme data from which to retrieve default values.
* @return the default value for the specified color.
* @see #addDefaultValuesListener(ThemeListener)
*/
private static Color getDefaultColor(int id, ThemeData data) {
// Makes sure id is a legal color identifier.
checkColorIdentifier(id);
return COLORS.get(Integer.valueOf(id)).getColor(data);
}
/**
* Returns the default value for the specified font.
* <p>
* Default values are look&feel dependant, and are subject to change during the application's
* life time.<br/>
* Classes that need to monitor such changes can register themselves using {@link #addDefaultValuesListener(ThemeListener)}.
* </p>
* @param id identifier of the font whose default value should be retrieved.
* @return the default value for the specified font.
* @see #addDefaultValuesListener(ThemeListener)
*/
private static Font getDefaultFont(int id, ThemeData data) {
checkFontIdentifier(id);
return FONTS.get(Integer.valueOf(id)).getFont(data);
}
// - Comparison ----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Returns <code>true</code> if the specified data and the current one are identical.
* <p>
* Comparisons is done by calling {@link #isFontDifferent(int,Font,boolean)} and {@link #isColorDifferent(int,Color,boolean)}
* on every font and color. Refer to the documentation of these methods for more information on using the <code>ignoreDefaults</code>
* parameter.
* </p>
* @param data data against which to compare.
* @param ignoreDefaults whether or not to compare default values.
* @return <code>true</code> if the specified data and the current one are identical, <code>false</code> otherwise.
* @see #isFontDifferent(int,Font,boolean)
* @see #isColorDifferent(int,Color,boolean)
*/
public boolean isIdentical(ThemeData data, boolean ignoreDefaults) {
int i;
// Compares the colors.
for(i = 0; i < COLOR_COUNT; i++)
if(isColorDifferent(i, data.colors[i] , ignoreDefaults))
return false;
// Compares the fonts.
for(i = 0; i < FONT_COUNT; i++)
if(isFontDifferent(i, data.fonts[i], ignoreDefaults))
return false;
return true;
}
/**
* Returns <code>true</code> if the current data is identical to the specified one, using default values when items haven't been set.
* <p>
* This is a convenience method, and is strictly equivalent to calling {@link #isIdentical(ThemeData,boolean) isIdentical(data, false)}.
* </p>
* @param data data against which to compare.
* @return <code>true</code> if the specified data and the current one are identical, <code>false</code> otherwise.
*/
public boolean isIdentical(ThemeData data) {return isIdentical(data, false);}
/**
* Checks whether the current font and the specified one are different from one another.
* <p>
* This is a convenience method, and is stricly equivalent to calling
* <code>{@link #isFontDifferent(int,Font,boolean) isFontDifferent(}id, font, false)</code>.
* </p>
* @param id identifier of the font to check.
* @param font font to check.
* @return <code>true</code> if <code>font</code> is different from the one defined in the data.
* @see #isFontDifferent(int,Font,boolean)
* @see #isColorDifferent(int,Color)
*/
public boolean isFontDifferent(int id, Font font) {return isFontDifferent(id, font, false);}
/**
* Checks whether the current font and the specified one are different from one another.
* <p>
* Setting <code>ignoreDefaults</code> to <code>false</code> will compare both fonts from a 'user' point of view: comparison
* will be done on the values that are used by the rest of the application. It might however be necessary to consider
* fonts to be different if one is set but not the other. This can be achieved by setting <code>ignoreDefaults</code> to <code>true</code>.
* </p>
* @param id identifier of the font to check.
* @param font font to check.
* @param ignoreDefaults whether or not to ignore defaults if the requested item doesn't have a value.
* @return <code>true</code> if <code>font</code> is different from the one defined in the data.
* @see #isFontDifferent(int,Font)
* @see #isColorDifferent(int,Color)
*/
public synchronized boolean isFontDifferent(int id, Font font, boolean ignoreDefaults) {
checkFontIdentifier(id);
// If the specified font is null, the only way for both fonts to be equal is for fonts[id]
// to be null as well.
if(font == null)
return fonts[id] != null;
// If fonts[id] is null and we're set to ignore defaults, both fonts are different.
// If we're set to use defaults, we must compare font and the default value for id.
if(fonts[id] == null)
return ignoreDefaults || !getDefaultFont(id, this).equals(font);
// 'Standard' case: both fonts are set, compare them normally.
return !font.equals(fonts[id]);
}
/**
* Checks whether the current color and the specified one are different from one another.
* <p>
* This is a convenience method, and is stricly equivalent to calling
* <code>{@link #isColorDifferent(int,Color,boolean) isColorDifferent(}id, color, false)</code>.
* </p>
* @param id identifier of the color to check.
* @param color color to check.
* @return <code>true</code> if <code>color</code> is different from the one defined in the data.
* @see #isColorDifferent(int,Color,boolean)
* @see #isFontDifferent(int,Font)
*/
public boolean isColorDifferent(int id, Color color) {return isColorDifferent(id, color, false);}
/**
* Checks whether the current color and the specified one are different from one another.
* <p>
* Setting <code>ignoreDefaults</code> to <code>false</code> will compare both colors from a 'user' point of view: comparison
* will be done on the values that are used by the rest of the application. It might however be necessary to consider
* colors to be different if one is set but not the other. This can be achieved by setting <code>ignoreDefaults</code> to <code>true</code>.
* </p>
* @param id identifier of the color to check.
* @param color color to check.
* @param ignoreDefaults whether or not to ignore defaults if the requested item doesn't have a value.
* @return <code>true</code> if <code>color</code> is different from the one defined in the data.
* @see #isColorDifferent(int,Color)
* @see #isFontDifferent(int,Font)
*/
public synchronized boolean isColorDifferent(int id, Color color, boolean ignoreDefaults) {
checkColorIdentifier(id);
// If the specified color is null, the only way for both colors to be equal is for colors[id]
// to be null as well.
if(color == null)
return colors[id] != null;
// If colors[id] is null and we're set to ignore defaults, both colors are different.
// If we're set to use defaults, we must compare color and the default value for id.
if(colors[id] == null)
return ignoreDefaults || !getDefaultColor(id, this).equals(color);
// 'Standard' case: both colors are set, compare them normally.
return !color.equals(colors[id]);
}
// - Theme events --------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Registers the specified theme listener.
* <p>
* The listener will receive {@link FontChangedEvent font} and {@link ColorChangedEvent color} events whenever
* one of the default values has been changed, by a modification to the current look&feel for example.
* </p>
* <p>
* It is not necessary for 'themable' components to listen to default values, as they are automatically propagated
* through {@link Theme} and {@link ThemeManager}.
* </p>
* <p>
* Note that listeners are stored as weak references, to make sure that the API doesn't keep ghost copies of objects
* whose usefulness is long since past. This forces callers to make sure they keep a copy of the listener's instance: if
* they do not, the instance will be weakly linked and garbage collected out of existence.
* </p>
* @param listener theme listener to register.
* @see #removeDefaultValuesListener(ThemeListener)
*/
public static void addDefaultValuesListener(ThemeListener listener) {listeners.put(listener, null);}
/**
* Removes the specified instance from the list of registered theme listeners.
* <p>
* Note that since listeners are stored as weak references, calling this method is not strictly necessary. As soon
* as a listener instance is not referenced anymore, it will automatically be caught and destroyed by the garbage
* collector.
* </p>
* @param listener instance to remove from the list of registered theme listeners.
* @see #addDefaultValuesListener(ThemeListener)
*/
public static void removeDefaultValuesListener(ThemeListener listener) {listeners.remove(listener);}
/**
* Dispatches a {@link FontChangedEvent} to all registered listeners.
* @param id identifier of the font that changed.
* @param font new value for the font that changed.
*/
static void triggerFontEvent(int id, Font font) {
FontChangedEvent event; // Event that will be dispatched.
// Creates the event.
event = new FontChangedEvent(null, id, font);
// Dispatches it.
for(ThemeListener listener : listeners.keySet())
listener.fontChanged(event);
}
/**
* Dispatches a {@link ColorChangedEvent} to all registered listeners.
* @param id identifier of the color that changed.
* @param color new value for the color that changed.
*/
static void triggerColorEvent(int id, Color color) {
ColorChangedEvent event; // Event that will be dispatched.
// Creates the event.
event = new ColorChangedEvent(null, id, color);
// Dispatches it.
for(ThemeListener listener : listeners.keySet())
listener.colorChanged(event);
}
// - Helper methods ------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------
/**
* Checks whether the specified color identifier is legal.
* @param id identifier to check against.
* @throws IllegalArgumentException if <code>id</code> is not a legal color identifier.
*/
private static void checkColorIdentifier(int id) {
if(id < 0 || id >= COLOR_COUNT)
throw new IllegalArgumentException("Illegal color identifier: " + id);
}
/**
* Checks whether the specified font identifier is legal.
* @param id identifier to check against.
* @throws IllegalArgumentException if <code>id</code> is not a legal font identifier.
*/
private static void checkFontIdentifier(int id) {
if(id < 0 || id >= FONT_COUNT)
throw new IllegalArgumentException("Illegal font identifier: " + id);
}
}