/* * 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 * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.gui.dock.facile.menu; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JFrame; import javax.swing.JRadioButtonMenuItem; import javax.swing.LookAndFeel; import bibliothek.gui.dock.support.lookandfeel.ComponentCollector; import bibliothek.gui.dock.support.lookandfeel.LookAndFeelList; import bibliothek.gui.dock.support.lookandfeel.LookAndFeelListener; import bibliothek.gui.dock.support.lookandfeel.LookAndFeelList.Info; import bibliothek.gui.dock.support.menu.BaseMenuPiece; import bibliothek.util.ClientOnly; /** * A menu that contains an item for each available {@link LookAndFeel}. The * set of <code>LookAndFeel</code>s is determined through a {@link LookAndFeelList}. * @author Benjamin Sigg */ @ClientOnly public class LookAndFeelMenuPiece extends BaseMenuPiece{ /** the item for the default-<code>LookAndFeel</code> */ private JRadioButtonMenuItem defaultButton; /** the item for the systems imitating <code>LookAndFeel</code> */ private JRadioButtonMenuItem systemButton; /** a list of buttons, one for each {@link LookAndFeel} */ private Map<Info, JRadioButtonMenuItem> buttons = new HashMap<Info, JRadioButtonMenuItem>(); /** the list of available <code>LookAndFeel</code>s */ private LookAndFeelList list; /** a listener to {@link #list} */ private ListListener listListener = new ListListener(); /** whether the <code>LookAndFeel</code> is currently changing or not */ private boolean onChange = false; /** a collector monitoring the {@link JFrame} that is given to the constructor of this menu */ private ComponentCollector frameCollector; /** * Creates a new menu. */ public LookAndFeelMenuPiece(){ this( null, null ); } /** * Creates a new menu. * @param frame the main frame of the application. This piece will add * a listener to <code>frame</code> and free resources the moment * <code>frame</code> is closed. This menu will also ensure that <code>frame</code>s * user interface is updated when the {@link javax.swing.LookAndFeel} changes. * Can be <code>null</code>. * @param list the set of available {@link LookAndFeel}s. Can be <code>null</code>. */ public LookAndFeelMenuPiece( final JFrame frame, LookAndFeelList list ){ if( list == null ) list = LookAndFeelList.getDefaultList(); this.list = list; defaultButton = new JRadioButtonMenuItem( "Default: " + list.getDefault().getName() ); defaultButton.addItemListener( new SetListener( defaultButton, list.getDefault() )); add( defaultButton ); systemButton = new JRadioButtonMenuItem( list.getSystem().getName() ); systemButton.addItemListener( new SetListener( systemButton, list.getSystem() )); add( systemButton ); addSeparator(); for( int i = 0, n = list.size(); i < n; i++ ){ Info info = list.get( i ); JRadioButtonMenuItem item = new JRadioButtonMenuItem( info.getName() ); buttons.put( info, item ); SetListener listener = new SetListener( item, info ); item.addItemListener( listener ); add( item ); } if( frame != null ){ frameCollector = new ComponentCollector(){ public Collection<Component> listComponents(){ List<Component> result = new ArrayList<Component>(); result.add( frame ); return result; } }; } changed(); } @Override public void bind(){ if( !isBound() ){ super.bind(); install(); } } @Override public void unbind(){ if( isBound() ){ super.unbind(); uninstall(); } } private void install(){ if( frameCollector != null ){ list.addComponentCollector( frameCollector ); } list.addLookAndFeelListener( listListener ); changed(); } private void uninstall(){ if( frameCollector != null ){ list.removeComponentCollector( frameCollector ); } list.removeLookAndFeelListener( listListener ); } /** * Frees resources and cuts connections to other objects such that this * piece can be removed by the garbage collector. * @deprecated the method {@link #unbind()} is automatically called if this menu is no * longer visible, that method will also uninstall resources */ @Deprecated public void destroy(){ list.removeLookAndFeelListener( listListener ); } /** * Gets the list of {@link LookAndFeel}s. * @return the list */ public LookAndFeelList getList() { return list; } /** * Called when the {@link LookAndFeel} has been changed. Ensures * that the correct items in this menu are selected. */ private void changed(){ onChange = true; Info current = list.getLookAndFeel(); defaultButton.setSelected( list.getDefault() == current ); systemButton.setSelected( list.getSystem() == current ); for( Map.Entry<Info, JRadioButtonMenuItem> entry : buttons.entrySet() ){ entry.getValue().setSelected( current == entry.getKey() ); } onChange = false; } /** * A listener to the {@link LookAndFeelList}, informing this piece * when the LookAndFeel changes. * @author Benjamin Sigg * */ private class ListListener implements LookAndFeelListener{ public void lookAndFeelChanged( LookAndFeelList list, Info lookAndFeel ) { changed(); } public void defaultLookAndFeelChanged( LookAndFeelList list, Info lookAndFeel ) { defaultButton.setText( lookAndFeel.getName() ); } public void systemLookAndFeelChanged( LookAndFeelList list, Info lookAndFeel ) { systemButton.setText( lookAndFeel.getName() ); } public void lookAndFeelAdded( LookAndFeelList list, Info info ) { JRadioButtonMenuItem item = new JRadioButtonMenuItem( info.getName() ); buttons.put( info, item ); SetListener listener = new SetListener( item, info ); item.addItemListener( listener ); add( item ); } public void lookAndFeelRemoved( LookAndFeelList list, Info lookAndFeel ) { JRadioButtonMenuItem item = buttons.remove( lookAndFeel ); if( item != null ) remove( item ); } } /** * A listener to one item of a {@link LookAndFeelMenuPiece}, this listener * exchanges the {@link LookAndFeel} when the observed item is clicked. * @author Benjamin Sigg * */ private class SetListener implements ItemListener{ /** the observed item */ private JRadioButtonMenuItem item; /** the {@link LookAndFeel} */ private Info info; /** * Creates a new listener. The listener is not added to * item, that's the responsibility of the client. * @param item the item that will be observed * @param info the {@link LookAndFeel} that will be used * when <code>item</code> is clicked */ public SetListener( JRadioButtonMenuItem item, Info info ){ this.info = info; this.item = item; } public void itemStateChanged( ItemEvent e ) { if( !onChange ){ if( item.isSelected() ) list.setLookAndFeel( info ); else item.setSelected( true ); } } } }