/*
* 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 java.awt.Color;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.io.InputStream;
import java.util.StringTokenizer;
import javax.xml.parsers.SAXParserFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Loads theme instances from properly formatted XML files.
* @author Nicolas Rinaudo
*/
class ThemeReader extends DefaultHandler implements ThemeXmlConstants {
private static final Logger LOGGER = LoggerFactory.getLogger(ThemeReader.class);
// - XML parser states ---------------------------------------------------------------
// -----------------------------------------------------------------------------------
/** Parsing hasn't started yet. */
private static final int STATE_UNKNOWN = 0;
/** Parsing the root element. */
private static final int STATE_ROOT = 1;
/** Parsing the table element.*/
private static final int STATE_TABLE = 2;
/** Parsing the shell element. */
private static final int STATE_SHELL = 3;
/** Parsing the editor element. */
private static final int STATE_EDITOR = 4;
/** Parsing the location bar element. */
private static final int STATE_LOCATION_BAR = 5;
/** Parsing the shell.normal element. */
private static final int STATE_SHELL_NORMAL = 6;
/** Parsing the shell.selected element. */
private static final int STATE_SHELL_SELECTED = 7;
/** Parsing the editor.normal element. */
private static final int STATE_EDITOR_NORMAL = 8;
/** Parsing the location bar.normal element. */
private static final int STATE_LOCATION_BAR_NORMAL = 9;
/** Parsing the editor.selected element. */
private static final int STATE_EDITOR_SELECTED = 10;
/** Parsing the location bar.selected element. */
private static final int STATE_LOCATION_BAR_SELECTED = 11;
/** Parsing the shell_history element. */
private static final int STATE_SHELL_HISTORY = 12;
/** Parsing the shell_history.normal element. */
private static final int STATE_SHELL_HISTORY_NORMAL = 13;
/** Parsing the shell_history.selected element. */
private static final int STATE_SHELL_HISTORY_SELECTED = 14;
/** Parsing the volume_label element. */
private static final int STATE_STATUS_BAR = 15;
private static final int STATE_HIDDEN = 16;
private static final int STATE_HIDDEN_NORMAL = 17;
private static final int STATE_HIDDEN_SELECTED = 18;
private static final int STATE_FOLDER = 19;
private static final int STATE_FOLDER_NORMAL = 20;
private static final int STATE_FOLDER_SELECTED = 21;
private static final int STATE_ARCHIVE = 22;
private static final int STATE_ARCHIVE_NORMAL = 23;
private static final int STATE_ARCHIVE_SELECTED = 24;
private static final int STATE_SYMLINK = 25;
private static final int STATE_SYMLINK_NORMAL = 26;
private static final int STATE_SYMLINK_SELECTED = 27;
private static final int STATE_MARKED = 28;
private static final int STATE_MARKED_NORMAL = 29;
private static final int STATE_MARKED_SELECTED = 30;
private static final int STATE_FILE = 31;
private static final int STATE_FILE_NORMAL = 32;
private static final int STATE_FILE_SELECTED = 33;
private static final int STATE_TABLE_NORMAL = 34;
private static final int STATE_TABLE_SELECTED = 35;
private static final int STATE_TABLE_ALTERNATE = 36;
private static final int STATE_TABLE_UNMATCHED = 37;
/** Parsing the quick list element. */
private static final int STATE_QUICK_LIST = 38;
/** Parsing the quick list header element. */
private static final int STATE_QUICK_LIST_HEADER = 39;
/** Parsing the quick list item element. */
private static final int STATE_QUICK_LIST_ITEM = 40;
private static final int STATE_QUICK_LIST_ITEM_NORMAL = 41;
private static final int STATE_QUICK_LIST_ITEM_SELECTED = 42;
// - Instance variables --------------------------------------------------------------
// -----------------------------------------------------------------------------------
/** Theme template that is currently being built. */
private ThemeData template;
/** Current state of the XML parser. */
private int state;
/** Used to ignore the content of an unknown tag. */
private String unknownElement;
// - Initialisation ------------------------------------------------------------------
// -----------------------------------------------------------------------------------
/**
* Creates a new theme reader.
*/
private ThemeReader(ThemeData t) {
template = t;
state = STATE_UNKNOWN;
}
/**
* Attempts to read a theme from the specified input stream.
* @param in where to read the theme from.
* @param template template in which to store the data.
* @exception Exception thrown if an error occured while reading the template.
*/
public static void read(InputStream in, ThemeData template) throws Exception {SAXParserFactory.newInstance().newSAXParser().parse(in, new ThemeReader(template));}
// - XML interaction -----------------------------------------------------
// -----------------------------------------------------------------------
/**
* Notifies the reader that a new XML element is starting.
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// Ignores the content of unknown elements.
if(unknownElement != null) {
LOGGER.debug("Ignoring element " + qName);
return;
}
// XML root element.
if(qName.equals(ELEMENT_ROOT)) {
if(state != STATE_UNKNOWN)
traceIllegalDeclaration(ELEMENT_ROOT);
state = STATE_ROOT;
}
// File table declaration.
else if(qName.equals(ELEMENT_TABLE)) {
if(state != STATE_ROOT)
traceIllegalDeclaration(qName);
state = STATE_TABLE;
}
// Shell declaration.
else if(qName.equals(ELEMENT_SHELL)) {
if(state != STATE_ROOT)
traceIllegalDeclaration(qName);
state = STATE_SHELL;
}
// Editor declaration.
else if(qName.equals(ELEMENT_EDITOR)) {
if(state != STATE_ROOT)
traceIllegalDeclaration(qName);
state = STATE_EDITOR;
}
// Location bar declaration.
else if(qName.equals(ELEMENT_LOCATION_BAR)) {
if(state != STATE_ROOT)
traceIllegalDeclaration(qName);
state = STATE_LOCATION_BAR;
}
// Quick list declaration.
else if(qName.equals(ELEMENT_QUICK_LIST)) {
if(state != STATE_ROOT)
traceIllegalDeclaration(qName);
state = STATE_QUICK_LIST;
}
// Shell history declaration.
else if(qName.equals(ELEMENT_SHELL_HISTORY)) {
if(state != STATE_ROOT)
traceIllegalDeclaration(qName);
state = STATE_SHELL_HISTORY;
}
// Volume label declaration.
else if(qName.equals(ELEMENT_STATUS_BAR)) {
if(state != STATE_ROOT)
traceIllegalDeclaration(qName);
state = STATE_STATUS_BAR;
}
else if(qName.equals(ELEMENT_HIDDEN)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_HIDDEN;
}
else if(qName.equals(ELEMENT_FOLDER)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_FOLDER;
}
else if(qName.equals(ELEMENT_ARCHIVE)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_ARCHIVE;
}
else if(qName.equals(ELEMENT_SYMLINK)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_SYMLINK;
}
else if(qName.equals(ELEMENT_MARKED)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_MARKED;
}
else if(qName.equals(ELEMENT_FILE)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_FILE;
}
else if(qName.equals(ELEMENT_ALTERNATE)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_TABLE_ALTERNATE;
}
// Header declaration.
else if(qName.equals(ELEMENT_HEADER)) {
if(state == STATE_QUICK_LIST)
state = STATE_QUICK_LIST_HEADER;
else
traceIllegalDeclaration(qName);
}
// Item declaration.
else if(qName.equals(ELEMENT_ITEM)) {
if(state == STATE_QUICK_LIST)
state = STATE_QUICK_LIST_ITEM;
else
traceIllegalDeclaration(qName);
}
// Normal element declaration.
else if(qName.equals(ELEMENT_NORMAL)) {
if(state == STATE_SHELL)
state = STATE_SHELL_NORMAL;
else if(state == STATE_EDITOR)
state = STATE_EDITOR_NORMAL;
else if(state == STATE_LOCATION_BAR)
state = STATE_LOCATION_BAR_NORMAL;
else if(state == STATE_SHELL_HISTORY)
state = STATE_SHELL_HISTORY_NORMAL;
else if(state == STATE_HIDDEN)
state = STATE_HIDDEN_NORMAL;
else if(state == STATE_FOLDER)
state = STATE_FOLDER_NORMAL;
else if(state == STATE_ARCHIVE)
state = STATE_ARCHIVE_NORMAL;
else if(state == STATE_SYMLINK)
state = STATE_SYMLINK_NORMAL;
else if(state == STATE_MARKED)
state = STATE_MARKED_NORMAL;
else if(state == STATE_FILE)
state = STATE_FILE_NORMAL;
else if(state == STATE_TABLE)
state = STATE_TABLE_NORMAL;
else if(state == STATE_QUICK_LIST_ITEM)
state = STATE_QUICK_LIST_ITEM_NORMAL;
else
traceIllegalDeclaration(qName);
}
// Selected element declaration.
else if(qName.equals(ELEMENT_SELECTED)) {
if(state == STATE_SHELL)
state = STATE_SHELL_SELECTED;
else if(state == STATE_EDITOR)
state = STATE_EDITOR_SELECTED;
else if(state == STATE_LOCATION_BAR)
state = STATE_LOCATION_BAR_SELECTED;
else if(state == STATE_SHELL_HISTORY)
state = STATE_SHELL_HISTORY_SELECTED;
else if(state == STATE_HIDDEN)
state = STATE_HIDDEN_SELECTED;
else if(state == STATE_FOLDER)
state = STATE_FOLDER_SELECTED;
else if(state == STATE_ARCHIVE)
state = STATE_ARCHIVE_SELECTED;
else if(state == STATE_SYMLINK)
state = STATE_SYMLINK_SELECTED;
else if(state == STATE_MARKED)
state = STATE_MARKED_SELECTED;
else if(state == STATE_FILE)
state = STATE_FILE_SELECTED;
else if(state == STATE_TABLE)
state = STATE_TABLE_SELECTED;
else if(state == STATE_QUICK_LIST_ITEM)
state = STATE_QUICK_LIST_ITEM_SELECTED;
else
traceIllegalDeclaration(qName);
}
// Font creation.
else if(qName.equals(ELEMENT_FONT)) {
if(state == STATE_SHELL)
template.setFont(ThemeData.SHELL_FONT, createFont(attributes));
else if(state == STATE_EDITOR)
template.setFont(ThemeData.EDITOR_FONT, createFont(attributes));
else if(state == STATE_LOCATION_BAR)
template.setFont(ThemeData.LOCATION_BAR_FONT, createFont(attributes));
else if(state == STATE_SHELL_HISTORY)
template.setFont(ThemeData.SHELL_HISTORY_FONT, createFont(attributes));
else if(state == STATE_STATUS_BAR)
template.setFont(ThemeData.STATUS_BAR_FONT, createFont(attributes));
else if(state == STATE_TABLE)
template.setFont(ThemeData.FILE_TABLE_FONT, createFont(attributes));
else if(state == STATE_QUICK_LIST_HEADER)
template.setFont(ThemeData.QUICK_LIST_HEADER_FONT, createFont(attributes));
else if(state == STATE_QUICK_LIST_ITEM)
template.setFont(ThemeData.QUICK_LIST_ITEM_FONT, createFont(attributes));
else
traceIllegalDeclaration(qName);
}
// Unfocused background color.
else if(qName.equals(ELEMENT_INACTIVE_BACKGROUND)) {
if(state == STATE_TABLE_NORMAL)
template.setColor(ThemeData.FILE_TABLE_INACTIVE_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_TABLE_SELECTED)
template.setColor(ThemeData.FILE_TABLE_INACTIVE_SELECTED_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_TABLE_ALTERNATE)
template.setColor(ThemeData.FILE_TABLE_INACTIVE_ALTERNATE_BACKGROUND_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// Secondary background.
else if(qName.equals(ELEMENT_SECONDARY_BACKGROUND)) {
if(state == STATE_TABLE_SELECTED)
template.setColor(ThemeData.FILE_TABLE_SELECTED_SECONDARY_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_QUICK_LIST_HEADER)
template.setColor(ThemeData.QUICK_LIST_HEADER_SECONDARY_BACKGROUND_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// Inactive secondary background.
else if(qName.equals(ELEMENT_INACTIVE_SECONDARY_BACKGROUND)) {
if(state == STATE_TABLE_SELECTED)
template.setColor(ThemeData.FILE_TABLE_INACTIVE_SELECTED_SECONDARY_BACKGROUND_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// Unfocused foreground color.
else if(qName.equals(ELEMENT_INACTIVE_FOREGROUND)) {
if(state == STATE_FILE_NORMAL)
template.setColor(ThemeData.FILE_INACTIVE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_FOLDER_NORMAL)
template.setColor(ThemeData.FOLDER_INACTIVE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_ARCHIVE_NORMAL)
template.setColor(ThemeData.ARCHIVE_INACTIVE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SYMLINK_NORMAL)
template.setColor(ThemeData.SYMLINK_INACTIVE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_HIDDEN_NORMAL)
template.setColor(ThemeData.HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_MARKED_NORMAL)
template.setColor(ThemeData.MARKED_INACTIVE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_FILE_SELECTED)
template.setColor(ThemeData.FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_FOLDER_SELECTED)
template.setColor(ThemeData.FOLDER_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_ARCHIVE_SELECTED)
template.setColor(ThemeData.ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SYMLINK_SELECTED)
template.setColor(ThemeData.SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_HIDDEN_SELECTED)
template.setColor(ThemeData.HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_MARKED_SELECTED)
template.setColor(ThemeData.MARKED_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// File table border color.
else if(qName.equals(ELEMENT_BORDER)) {
if(state == STATE_TABLE)
template.setColor(ThemeData.FILE_TABLE_BORDER_COLOR, createColor(attributes));
else if(state == STATE_STATUS_BAR)
template.setColor(ThemeData.STATUS_BAR_BORDER_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// File table inactive border color.
else if(qName.equals(ELEMENT_INACTIVE_BORDER)) {
if(state == STATE_TABLE)
template.setColor(ThemeData.FILE_TABLE_INACTIVE_BORDER_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// File table outline color.
else if(qName.equals(ELEMENT_OUTLINE)) {
if(state == STATE_TABLE)
template.setColor(ThemeData.FILE_TABLE_SELECTED_OUTLINE_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// File table inactive outline color.
else if(qName.equals(ELEMENT_INACTIVE_OUTLINE)) {
if(state == STATE_TABLE)
template.setColor(ThemeData.FILE_TABLE_INACTIVE_SELECTED_OUTLINE_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// Unmatched file table.
else if(qName.equals(ELEMENT_UNMATCHED)) {
if(state != STATE_TABLE)
traceIllegalDeclaration(qName);
state = STATE_TABLE_UNMATCHED;
}
// Background color.
else if(qName.equals(ELEMENT_BACKGROUND)) {
if(state == STATE_TABLE_NORMAL)
template.setColor(ThemeData.FILE_TABLE_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_TABLE_SELECTED)
template.setColor(ThemeData.FILE_TABLE_SELECTED_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_TABLE_ALTERNATE)
template.setColor(ThemeData.FILE_TABLE_ALTERNATE_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_TABLE_UNMATCHED)
template.setColor(ThemeData.FILE_TABLE_UNMATCHED_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_NORMAL)
template.setColor(ThemeData.SHELL_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_SELECTED)
template.setColor(ThemeData.SHELL_SELECTED_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_EDITOR_NORMAL)
template.setColor(ThemeData.EDITOR_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_EDITOR_SELECTED)
template.setColor(ThemeData.EDITOR_SELECTED_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_LOCATION_BAR_NORMAL)
template.setColor(ThemeData.LOCATION_BAR_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_LOCATION_BAR_SELECTED)
template.setColor(ThemeData.LOCATION_BAR_SELECTED_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_HISTORY_NORMAL)
template.setColor(ThemeData.SHELL_HISTORY_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_HISTORY_SELECTED)
template.setColor(ThemeData.SHELL_HISTORY_SELECTED_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_STATUS_BAR)
template.setColor(ThemeData.STATUS_BAR_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_QUICK_LIST_HEADER)
template.setColor(ThemeData.QUICK_LIST_HEADER_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_QUICK_LIST_ITEM_NORMAL)
template.setColor(ThemeData.QUICK_LIST_ITEM_BACKGROUND_COLOR, createColor(attributes));
else if(state == STATE_QUICK_LIST_ITEM_SELECTED)
template.setColor(ThemeData.QUICK_LIST_SELECTED_ITEM_BACKGROUND_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// Progress bar color.
else if(qName.equals(ELEMENT_PROGRESS)) {
if(state == STATE_LOCATION_BAR)
template.setColor(ThemeData.LOCATION_BAR_PROGRESS_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// 'OK' color.
else if(qName.equals(ELEMENT_OK)) {
if(state == STATE_STATUS_BAR)
template.setColor(ThemeData.STATUS_BAR_OK_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// 'WARNING' color.
else if(qName.equals(ELEMENT_WARNING)) {
if(state == STATE_STATUS_BAR)
template.setColor(ThemeData.STATUS_BAR_WARNING_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// 'CRITICAL' color.
else if(qName.equals(ELEMENT_CRITICAL)) {
if(state == STATE_STATUS_BAR)
template.setColor(ThemeData.STATUS_BAR_CRITICAL_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
// Text color.
else if(qName.equals(ELEMENT_FOREGROUND)) {
if(state == STATE_HIDDEN_NORMAL)
template.setColor(ThemeData.HIDDEN_FILE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_HIDDEN_SELECTED)
template.setColor(ThemeData.HIDDEN_FILE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_TABLE_UNMATCHED)
template.setColor(ThemeData.FILE_TABLE_UNMATCHED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_FOLDER_NORMAL)
template.setColor(ThemeData.FOLDER_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_FOLDER_SELECTED)
template.setColor(ThemeData.FOLDER_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_ARCHIVE_NORMAL)
template.setColor(ThemeData.ARCHIVE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_ARCHIVE_SELECTED)
template.setColor(ThemeData.ARCHIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SYMLINK_NORMAL)
template.setColor(ThemeData.SYMLINK_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SYMLINK_SELECTED)
template.setColor(ThemeData.SYMLINK_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_MARKED_NORMAL)
template.setColor(ThemeData.MARKED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_MARKED_SELECTED)
template.setColor(ThemeData.MARKED_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_FILE_NORMAL)
template.setColor(ThemeData.FILE_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_FILE_SELECTED)
template.setColor(ThemeData.FILE_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_NORMAL)
template.setColor(ThemeData.SHELL_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_SELECTED)
template.setColor(ThemeData.SHELL_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_HISTORY_NORMAL)
template.setColor(ThemeData.SHELL_HISTORY_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_SHELL_HISTORY_SELECTED)
template.setColor(ThemeData.SHELL_HISTORY_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_EDITOR_NORMAL)
template.setColor(ThemeData.EDITOR_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_EDITOR_SELECTED)
template.setColor(ThemeData.EDITOR_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_LOCATION_BAR_NORMAL)
template.setColor(ThemeData.LOCATION_BAR_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_LOCATION_BAR_SELECTED)
template.setColor(ThemeData.LOCATION_BAR_SELECTED_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_STATUS_BAR)
template.setColor(ThemeData.STATUS_BAR_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_QUICK_LIST_HEADER)
template.setColor(ThemeData.QUICK_LIST_HEADER_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_QUICK_LIST_ITEM_NORMAL)
template.setColor(ThemeData.QUICK_LIST_ITEM_FOREGROUND_COLOR, createColor(attributes));
else if(state == STATE_QUICK_LIST_ITEM_SELECTED)
template.setColor(ThemeData.QUICK_LIST_SELECTED_ITEM_FOREGROUND_COLOR, createColor(attributes));
else
traceIllegalDeclaration(qName);
}
else
traceIllegalDeclaration(qName);
}
/**
* Notifies the reader that the current element declaration is over.
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// If we're in an unknown element....
if(unknownElement != null) {
// If it just closed, resume normal parsing.
if(qName.equals(unknownElement))
unknownElement = null;
// Ignores all other tags.
else
return;
}
// XML root element.
if(qName.equals(ELEMENT_ROOT))
state = STATE_UNKNOWN;
// File table declaration.
else if(qName.equals(ELEMENT_TABLE))
state = STATE_ROOT;
else if(qName.equals(ELEMENT_ALTERNATE))
state = STATE_TABLE;
else if(qName.equals(ELEMENT_UNMATCHED))
state = STATE_TABLE;
else if(qName.equals(ELEMENT_HIDDEN))
state = STATE_TABLE;
else if(qName.equals(ELEMENT_FOLDER))
state = STATE_TABLE;
else if(qName.equals(ELEMENT_ARCHIVE))
state = STATE_TABLE;
else if(qName.equals(ELEMENT_SYMLINK))
state = STATE_TABLE;
else if(qName.equals(ELEMENT_MARKED))
state = STATE_TABLE;
else if(qName.equals(ELEMENT_FILE))
state = STATE_TABLE;
// Shell declaration.
else if(qName.equals(ELEMENT_SHELL))
state = STATE_ROOT;
// Shell history declaration.
else if(qName.equals(ELEMENT_SHELL_HISTORY))
state = STATE_ROOT;
// Editor declaration.
else if(qName.equals(ELEMENT_EDITOR))
state = STATE_ROOT;
// Location bar declaration.
else if(qName.equals(ELEMENT_LOCATION_BAR))
state = STATE_ROOT;
// Quick list declaration.
else if(qName.equals(ELEMENT_QUICK_LIST))
state = STATE_ROOT;
// Volume label declaration
else if(qName.equals(ELEMENT_STATUS_BAR))
state = STATE_ROOT;
// Header declaration.
else if(qName.equals(ELEMENT_HEADER)) {
if(state == STATE_QUICK_LIST_HEADER)
state = STATE_QUICK_LIST;
}
// Item declaration.
else if(qName.equals(ELEMENT_ITEM)) {
if(state == STATE_QUICK_LIST_ITEM)
state = STATE_QUICK_LIST;
}
// Normal element declaration.
else if(qName.equals(ELEMENT_NORMAL)) {
if(state == STATE_SHELL_NORMAL)
state = STATE_SHELL;
else if(state == STATE_SHELL_HISTORY_NORMAL)
state = STATE_SHELL_HISTORY;
else if(state == STATE_HIDDEN_NORMAL)
state = STATE_HIDDEN;
else if(state == STATE_FOLDER_NORMAL)
state = STATE_FOLDER;
else if(state == STATE_ARCHIVE_NORMAL)
state = STATE_ARCHIVE;
else if(state == STATE_SYMLINK_NORMAL)
state = STATE_SYMLINK;
else if(state == STATE_MARKED_NORMAL)
state = STATE_MARKED;
else if(state == STATE_FILE_NORMAL)
state = STATE_FILE;
else if(state == STATE_EDITOR_NORMAL)
state = STATE_EDITOR;
else if(state == STATE_LOCATION_BAR_NORMAL)
state = STATE_LOCATION_BAR;
else if(state == STATE_TABLE_NORMAL)
state = STATE_TABLE;
else if(state == STATE_QUICK_LIST_ITEM_NORMAL)
state = STATE_QUICK_LIST_ITEM;
}
// Selected element declaration.
else if(qName.equals(ELEMENT_SELECTED)) {
if(state == STATE_SHELL_SELECTED)
state = STATE_SHELL;
else if(state == STATE_SHELL_HISTORY_SELECTED)
state = STATE_SHELL_HISTORY;
else if(state == STATE_HIDDEN_SELECTED)
state = STATE_HIDDEN;
else if(state == STATE_FOLDER_SELECTED)
state = STATE_FOLDER;
else if(state == STATE_ARCHIVE_SELECTED)
state = STATE_ARCHIVE;
else if(state == STATE_SYMLINK_SELECTED)
state = STATE_SYMLINK;
else if(state == STATE_MARKED_SELECTED)
state = STATE_MARKED;
else if(state == STATE_FILE_SELECTED)
state = STATE_FILE;
else if(state == STATE_EDITOR_SELECTED)
state = STATE_EDITOR;
else if(state == STATE_LOCATION_BAR_SELECTED)
state = STATE_LOCATION_BAR;
else if(state == STATE_TABLE_SELECTED)
state = STATE_TABLE;
else if(state == STATE_QUICK_LIST_ITEM_SELECTED)
state = STATE_QUICK_LIST_ITEM;
}
}
// - Helper methods ------------------------------------------------------
// -----------------------------------------------------------------------
/**
* Checks whether the specified font is available on the system.
* @param font name of the font to check for.
* @return <code>true</code> if the font is available, <code>false</code> otherwise.
*/
private static boolean isFontAvailable(String font) {
String[] availableFonts; // All available fonts.
// Looks for the specified font.
availableFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
for (String availableFont : availableFonts)
if (availableFont.equalsIgnoreCase(font))
return true;
// Font doesn't exist on the system.
return false;
}
/**
* Creates a font from the specified XML attributes.
* <p>
* Ignored attributes will be set to their default values.
* </p>
* @param attributes XML attributes describing the font to use.
* @return the resulting Font instance.
*/
private static Font createFont(Attributes attributes) {
String buffer; // Buffer for attribute values.
int size; // Font size.
int style; // Font style.
StringTokenizer parser; // Used to parse the font family.
// Computes the font style.
style = 0;
if(((buffer = attributes.getValue(ATTRIBUTE_BOLD)) != null) && buffer.equals(VALUE_TRUE))
style |= Font.BOLD;
if(((buffer = attributes.getValue(ATTRIBUTE_ITALIC)) != null) && buffer.equals(VALUE_TRUE))
style |= Font.ITALIC;
// Computes the font size.
if((buffer = attributes.getValue(ATTRIBUTE_SIZE)) == null) {
LOGGER.debug("Missing font size attribute in theme, ignoring.");
return null;
}
size = Integer.parseInt(buffer);
// Computes the font family.
if((buffer = attributes.getValue(ATTRIBUTE_FAMILY)) == null) {
LOGGER.debug("Missing font family attribute in theme, ignoring.");
return null;
}
// Looks through the list of declared fonts to find one that is installed on the system.
parser = new StringTokenizer(buffer, ",");
while(parser.hasMoreTokens()) {
buffer = parser.nextToken().trim();
// Font was found, use it.
if(isFontAvailable(buffer))
return new Font(buffer, style, size);
}
// No font was found, instructs the ThemeManager to use the system default.
LOGGER.debug("Requested font families are not installed on the system, using default.");
return null;
}
/**
* Creates a color from the specified XML attributes.
* @param attributes XML attributes describing the font to use.
* @return the resulting Color instance.
*/
private static Color createColor(Attributes attributes) {
String buffer;
int color;
// Retrieves the color attribute's value.
if((buffer = attributes.getValue(ATTRIBUTE_COLOR)) == null) {
LOGGER.debug("Missing color attribute in theme, ignoring.");
return null;
}
color = Integer.parseInt(buffer, 16);
// Retrieves the transparency attribute's value..
if((buffer = attributes.getValue(ATTRIBUTE_ALPHA)) == null)
return new Color(color);
return new Color(color | (Integer.parseInt(buffer, 16) << 24), true);
}
// - Error generation methods --------------------------------------------
// -----------------------------------------------------------------------
private void traceIllegalDeclaration(String element) {
unknownElement = element;
LOGGER.debug("Unexpected start of element " + element + ", ignoring.");
}
}