All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bibliothek.gui.dock.support.lookandfeel.LookAndFeelList Maven / Gradle / Ivy

Go to download

DockingFrames is an open source Java Swing docking framework, licenced under LGPL 2.1. This is the same distribution as the original distribution (http://www.docking-frames.org/), only reinstalled in maven

There is a newer version: 1.1.2p20b.fix-1
Show newest version
/*
 * Bibliothek - DockingFrames
 * Library built on Java/Swing, allows the user to "drag and drop"
 * panels containing any Swing-Component the developer likes to add.
 * 
 * Copyright (C) 2007 Benjamin Sigg
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Benjamin Sigg
 * [email protected]
 * CH - Switzerland
 */
package bibliothek.gui.dock.support.lookandfeel;

import java.awt.Component;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.plaf.metal.DefaultMetalTheme;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.MetalTheme;

import bibliothek.util.Version;
import bibliothek.util.xml.XElement;

/**
 * A list of {@link LookAndFeel}s, can setup a LookAndFeel when
 * asked. It's possible to add a {@link LookAndFeelListener} to this list and
 * receive events whenever the LookAndFeel changes.
* Clients should use {@link #getDefaultList()} to get a list of {@link LookAndFeel}s * @author Benjamin Sigg */ public class LookAndFeelList{ /** global list of look and feels */ private static LookAndFeelList list; /** * Gets the global list of {@link LookAndFeel}s * @return the global list, not null */ public static LookAndFeelList getDefaultList(){ if( list == null ){ synchronized( LookAndFeelList.class ){ if( list == null ){ list = new LookAndFeelList(); } } } return list; } /** * Sets the default {@link LookAndFeelList}. * @param list the list, can be null */ public static void setDefaultList( LookAndFeelList list ){ LookAndFeelList.list = list; } /** the {@link LookAndFeel} used when no other LookAndFeel has been set */ private Wrapper defaultInfo; /** the {@link LookAndFeel} that imitates the system */ private Wrapper systemInfo; /** the {@link LookAndFeel} that is currently used */ private Info currentInfo; /** a list of available {@link LookAndFeel}s */ private List infos = new ArrayList(); /** the list of listeners that get informed when the LookAndFeel changes */ private List listeners = new ArrayList(); /** The roots of the {@link Component}-trees that need to be updated when the LookAndFeel changes */ private List componentCollectors = new ArrayList(); /** Whether the {@link #read(DataInputStream)}-method has effect when it is called a second time */ private boolean allowReadOnlyOnce = false; /** Whether the {@link #read(DataInputStream)}-method was called at least once */ private boolean hasRead = false; /** * Crates a new list and collects all available {@link LookAndFeel}s. */ protected LookAndFeelList(){ LookAndFeel feel = UIManager.getLookAndFeel(); setDefault( new Info( feel.getClass().getName(), feel.getName() )); currentInfo = defaultInfo; setSystem( new Info( UIManager.getSystemLookAndFeelClassName(), "System" )); LookAndFeelInfo[] preset = UIManager.getInstalledLookAndFeels(); for( int i = 0; i < preset.length; i++ ){ add( new Info( preset[i].getClassName(), preset[i].getName() )); } add( new Info( MetalLookAndFeel.class.getName(), "Retro" ){ private MetalTheme oldTheme; @Override protected void setup() { oldTheme = MetalLookAndFeel.getCurrentTheme(); MetalLookAndFeel.setCurrentTheme( new DefaultMetalTheme() ); } @Override protected void kill() { MetalLookAndFeel.setCurrentTheme( oldTheme ); } }); } /** * Whether multiple calls to {@link #read(DataInputStream)} have * an effect or not. * @return true if only the first read-call has an effect. */ public boolean isAllowReadOnlyOnce() { return allowReadOnlyOnce; } /** * Sets whether multiple calls to {@link #read(DataInputStream)} will * have an effect. * @param allowReadOnlyOnce true if only the first * read will have an effect, false if the {@link LookAndFeel} * can change every time {@link #read(DataInputStream)} is called. */ public void setAllowReadOnlyOnce( boolean allowReadOnlyOnce ) { this.allowReadOnlyOnce = allowReadOnlyOnce; } /** * Sets whether this list has already read something once, or whether * it is fresh. Can be used to reset a list to its initial state. * @param read true if at least one time one of the * read methods was called, false otherwise. */ public void setReadOnce( boolean read ){ hasRead = read; } /** * Adds a listener to this list, the listener will be notified * whenever the {@link LookAndFeel} is changed. * @param listener the new listener */ public void addLookAndFeelListener( LookAndFeelListener listener ){ if( listener == null ) throw new NullPointerException( "listener must not be null" ); listeners.add( listener ); } /** * Removes a listener from this list. * @param listener the listener to remove */ public void removeLookAndFeelListener( LookAndFeelListener listener ){ listeners.remove( listener ); } /** * Gets all {@link LookAndFeelListener} that are known to this list. * @return the list of listeners */ protected LookAndFeelListener[] listeners(){ return listeners.toArray( new LookAndFeelListener[ listeners.size() ] ); } /** * Adds a set of root-{@link Component}s to this list, the set of * roots will be used to find all {@link JComponent}s * which need to be updated when the {@link LookAndFeel} changes. * @param c the new set of roots */ public void addComponentCollector( ComponentCollector c ){ componentCollectors.add( c ); } /** * Removes an earlier added set of roots. * @param c the roots */ public void removeComponentCollector( ComponentCollector c ){ componentCollectors.remove( c ); } /** * Adds a new {@link LookAndFeel} to the list. * @param info the new LookAndFeel */ public void add( Info info ){ insert( infos.size(), info ); } /** * Inserts a new {@link LookAndFeel} into the list. * @param index the location of the new LookAndFeel * @param info the new LookAndFeel */ public void insert( int index, Info info ){ if( info == null ) throw new NullPointerException( "Info must not be null" ); infos.add( index, info ); for( LookAndFeelListener listener : listeners() ) listener.lookAndFeelAdded( this, info ); } /** * Gets the number of {@link LookAndFeel}s that are known to this list. * @return the number of LookAndFeels */ public int size(){ return infos.size(); } /** * Gets the index'th {@link LookAndFeel}. * @param index the location of the LookAndFeel * @return the LookAndFeel */ public Info get( int index ){ return infos.get( index ); } /** * Gets the location of info. * @param info a {@link LookAndFeel} * @return the location of info or -1 */ public int indexOf( Info info ){ return infos.indexOf( info ); } /** * Gets the index'th {@link LookAndFeel}, where 0 means the * {@link #getDefault() default}, 1 the {@link #getSystem() system} and * anything else the {@link #get(int) normal}, moved by 2 steps, LookAndFeels. * @param index the location of the LookAndFeel * @return the selected LookAndFeel */ public Info getFull( int index ){ if( index == 0 ) return getDefault(); if( index == 1 ) return getSystem(); return get( index-2 ); } /** * Gets the index of info, where 0 means the * {@link #getDefault() default}, 1 the {@link #getSystem() system} and * anything else the {@link #get(int) normal}, moved by 2 steps, LookAndFeels. * @param info the LookAndFeel to search * @return the location of info */ public int indexOfFull( Info info ){ if( info == defaultInfo ) return 0; if( info == systemInfo ) return 1; int index = indexOf( info ); if( index < 0 ) return -1; else return index+2; } /** * Gets the {@link LookAndFeel} whose unique identifier is key. * @param key the key to search * @return the handler of the {@link LookAndFeel} or null if key was not found */ public Info getFull( String key ){ if( "s.default".equals( key )) return getDefault(); if( "s.system".equals( key )) return getSystem(); for( Info info : infos ){ if( key.equals( keyOfFullNormal( info ) )){ return info; } } return null; } /** * Gets a unique identifier for info. * @param info the item whose identifier is searched * @return a unique identifier describing info */ public String keyOfFull( Info info ){ if( info == defaultInfo ) return "s.default"; if( info == systemInfo ) return "s.system"; return keyOfFullNormal( info ); } private String keyOfFullNormal( Info info ){ return "l." + info.getName().length() + "." + info.getName() + "." + info.className; } /** * Removes the {@link LookAndFeel} at location index from * this list. * @param info the LookAndFeel to remove */ public void remove( Info info ){ int index = indexOf( info ); if( index >= 0 ) remove( index ); } /** * Removes a {@link LookAndFeel} from this list. * @param index the location of the element to remove */ public void remove( int index ){ Info info = infos.remove( index ); for( LookAndFeelListener listener : listeners() ) listener.lookAndFeelRemoved( this, info ); } /** * Gets the {@link LookAndFeel} which is currently used. * @return the currently used LookAndFeel */ public Info getLookAndFeel() { return currentInfo; } /** * Exchanges the currently used {@link LookAndFeel}. * @param lookAndFeel information about a {@link LookAndFeel}, not null */ public void setLookAndFeel( Info lookAndFeel ){ if( lookAndFeel == currentInfo ) return; if( lookAndFeel == null ) throw new NullPointerException( "lookAndFeel must not be null" ); try { currentInfo.kill(); currentInfo = lookAndFeel; lookAndFeel.setup(); UIManager.setLookAndFeel( lookAndFeel.getClassName() ); LookAndFeelUtilities.updateUI( listComponents() ); for( LookAndFeelListener listener : listeners() ) listener.lookAndFeelChanged( this, lookAndFeel ); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } } /** * Gets information about the {@link LookAndFeel} that is used when * the system can decide on its own. * @return information about a {@link LookAndFeel} */ public Info getDefault() { return defaultInfo; } /** * Sets the default- {@link LookAndFeel}. Please note that {@link #getDefault()} * will return another {@link Info}, even if the behavior of that other * info is the same as defaultInfo. * @param defaultInfo the default LookAndFeel */ public void setDefault( Info defaultInfo ) { if( defaultInfo == null ) throw new NullPointerException( "argument must not be null" ); this.defaultInfo = new Wrapper( defaultInfo ); for( LookAndFeelListener listener : listeners() ) listener.defaultLookAndFeelChanged( this, this.defaultInfo ); } /** * Gets information about the {@link LookAndFeel} that imitates * the native look of the system. * @return information about a LookAndFeel */ public Info getSystem() { return systemInfo; } /** * Sets the system- {@link LookAndFeel}. Please note that {@link #getSystem()} * will return another {@link Info}, even if the behavior of that other * info is the same as systemInfo. * @param systemInfo the system LookAndFeel */ public void setSystem( Info systemInfo ) { if( systemInfo == null ) throw new NullPointerException( "argument must not be null" ); this.systemInfo = new Wrapper( systemInfo ); for( LookAndFeelListener listener : listeners() ) listener.systemLookAndFeelChanged( this, this.systemInfo ); } /** * Writes which {@link LookAndFeel} is currently used. * @param out the stream to write into * @throws IOException if the method can't write into out */ public void write( DataOutputStream out ) throws IOException { Version.write( out, Version.VERSION_1_1_1 ); out.writeUTF( keyOfFull( getLookAndFeel() ) ); } /** * Reads which {@link LookAndFeel} was used earlier and calls * {@link #setLookAndFeel(LookAndFeelList.Info) setLookAndFeel} * to set the old LookAndFeel. * @param in the stream to read from * @throws IOException if in can't be read */ public void read( DataInputStream in ) throws IOException { Version version = Version.read( in ); version.checkCurrent(); if( version.equals( Version.VERSION_1_0_4 )){ int index = in.readInt(); if( !hasRead || !allowReadOnlyOnce ){ if( index >= 0 && index < size()+2 ){ setLookAndFeel( getFull( index ) ); } } hasRead = true; } else{ String key = in.readUTF(); if( !hasRead || !allowReadOnlyOnce ){ Info laf = getFull( key ); if( laf == null ){ laf = getDefault(); } if( laf != null ){ setLookAndFeel( laf ); } } hasRead = true; } } /** * Writes which {@link LookAndFeel} is currently used. * @param element the element to write into, the attributes of * element will not be changed. */ public void writeXML( XElement element ){ element.addElement( "key" ).setString( keyOfFull( getLookAndFeel() ) ); } /** * Reads which {@link LookAndFeel} was used earlier and calls * {@link #setLookAndFeel(LookAndFeelList.Info) setLookAndFeel} * to set the old LookAndFeel. * @param element the element to read from */ public void readXML( XElement element ){ if( !hasRead || !allowReadOnlyOnce ){ XElement xkey = element.getElement( "key" ); Info info = null; if( xkey == null ){ XElement xindex = element.getElement( "index" ); int index = xindex.getInt(); if( index >= 0 && index < size()+2 ){ info = getFull( index ); } info = getFull( xindex.getInt() ); } else{ info = getFull( xkey.getString() ); } if( info == null ){ info = getDefault(); } if( info != null ){ setLookAndFeel( info ); } } hasRead = true; } /** * Creates a list containing all root-{@link Component}s of this application, * the {@link ComponentCollector}s are used to build this list. * @return the list of roots */ protected Collection listComponents(){ Collection list = new ArrayList(); for( ComponentCollector c : componentCollectors ) list.addAll( c.listComponents() ); return list; } /** * A wrapper around an {@link Info}. * @author Benjamin Sigg */ private class Wrapper extends Info{ /** the delegate */ private Info info; /** * Creates a new wrapper * @param info delegate to get information */ public Wrapper( Info info ) { super( info.getClassName(), info.getName() ); this.info = info; } @Override protected void setup() { info.setup(); } @Override protected void kill() { info.kill(); } } /** * Information about a {@link LookAndFeel}. * @author Benjamin Sigg */ public static class Info{ /** the class of the {@link LookAndFeel} that is represented by this Info */ private String className; /** the name of the LookAndFeel */ private String name; /** * Creates a new set of information * @param className the name of the class of the {@link LookAndFeel} * @param name the name of the LookAndFeel */ public Info( String className, String name ){ this.className = className; this.name = name; } /** * Gets the name of the class of a {@link LookAndFeel}. * @return the class name used for reflection */ public String getClassName() { return className; } /** * Gets the name of the {@link LookAndFeel} that is represented * by this Info. * @return the name */ public String getName() { return name; } /** * Informs this Info that its LookAndFeel * will be shown soon. */ protected void setup(){ // do nothing } /** * Informs this Info that its LookAndFeel * will be removed soon. */ protected void kill(){ // do nothing } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy