/*
* ToolBar.java
* Eisenkraut
*
* Copyright (c) 2004-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*/
package de.sciss.eisenkraut.gui;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.*;
import de.sciss.app.BasicEvent;
import de.sciss.app.EventManager;
/**
* Extension of <code>JPanel</code> that
* allows to add tool icons in a horizontal
* or vertical row. Listeners can be added to
* be informed about tool changes. Icons can
* be mutually exclusive grouped.
*/
@SuppressWarnings("serial")
public class ToolBar
extends JPanel // JToolBar
implements EventManager.Processor {
/**
* group mode : it is allowed that no
* button of a group is selected
*/
public static final int DESELECTION_ALLOWED = 0;
/**
* group mode : in a group there must
* be always one active button
*/
public static final int DESELECTION_FORBIDDEN = 1;
/**
* group mode : deselection is allowed when
* the group consists only of one element,
* otherwise deselection is forbidden
*/
public static final int DESELECTION_AUTO = -1;
private final HashMap<Integer, ToggleGroup> groups = new HashMap<Integer, ToggleGroup>(); // maps group numbers (Integer) to ToggleGroups
private final EventManager elm = new EventManager( this );
/**
* Creates an empty toolbar with the given orientation
*
* @param orient only <code>HORIZONTAL</code> at the moment
*/
public ToolBar( int orient )
{
super(); // (orient);
setLayout(new BoxLayout(this, orient == SwingConstants.HORIZONTAL ? BoxLayout.X_AXIS : BoxLayout.Y_AXIS));
// if( AbstractApplication.getApplication().getUserPrefs().getBoolean( PrefsUtil.KEY_INTRUDINGSIZE, false )) {
// setBorder( BorderFactory.createEmptyBorder( 0, 0, 0, 16 )); // account for intruding grow box
// }
// setFloatable(false);
// setBorder(null);
}
/**
* Adds a (non grouped) trigger button to the bar.
* The buttons focusable property will be set to <code>false</code>.
*
* @param button the button to add next to the last element
*/
public void addButton( AbstractButton button )
{
button.setFocusable( false );
add( button );
}
/**
* Changes the selection mode of a group.
*
* @param group group ID
* @param mode either <code>DESELECTION_ALLOWED</code>,
* <code>DESELECTION_FORBIDDEN</code> or <code>DESELECTION_AUTO</code>.
*
* @see #DESELECTION_ALLOWED
* @see #DESELECTION_FORBIDDEN
*/
public void setGroupMode(int group, int mode) {
Integer key = group;
ToggleGroup tg = groups.get(key);
if (tg != null) tg.setGroupMode(mode);
}
/**
* Adds a (grouped) toggle button to the bar.
* Selection mode depends on the
* group mode; the default is <code>DESELECTION_AUTO</code>.
* The buttons focusable property will be set to <code>false</code>.
*
* @param button the button to add next to the last element
* @param group the logical group ID for the button. All
* buttons of the group are mutual exclusively
* selectable.
*
* @see #setGroupMode( int, int )
*/
public void addToggleButton(JToggleButton button, int group) {
Integer key = group;
ToggleGroup tg = groups.get( key );
if (tg == null) {
tg = new ToggleGroup();
groups.put(key, tg);
}
button.setFocusable( false );
add( button );
tg.addToggleButton( button );
}
/**
* Adds a small spacing next to the last element to
* visually separate groups of buttons.
*/
public void addSeparator()
{
addSeparator( new Dimension( 8, 8 ));
}
public void addSeparator(Dimension d) {
add(Box.createRigidArea(d));
}
/**
* Registers a listener for receiving
* information about group selection changes.
* Note that only grouped toggle buttons are traced
* by the tool bar. The listener is informed if
* a button of a mutual group is toggled.
*
* @param listener the listener who wishes to be informed
*/
public void addToolActionListener( ToolActionListener listener )
{
elm.addListener( listener );
}
/**
* Unregisters a listener from receiving
* information about group selection changes.
*
* @param listener the listener who wishes to be removed from
* the event dispatcher
*/
public void removeToolActionListener( ToolActionListener listener )
{
elm.removeListener( listener );
}
/**
* This is called by the EventManager
* if new events are to be processed
*/
public void processEvent( BasicEvent e )
{
ToolActionListener listener;
int i;
for( i = 0; i < elm.countListeners(); i++ ) {
listener = (ToolActionListener) elm.getListener( i );
switch( e.getID() ) {
case ToolActionEvent.CHANGED:
listener.toolChanged( (ToolActionEvent) e );
break;
default:
assert false : e.getID();
break;
}
} // for( i = 0; i < elm.countListeners(); i++ )
}
// utility function to create and dispatch a ToolActionEvent
protected void dispatchChange( Object source, ToolAction action )
{
ToolActionEvent e = new ToolActionEvent( source, ToolActionEvent.CHANGED,
System.currentTimeMillis(), action );
elm.dispatchEvent( e );
}
private class ToggleGroup
implements ActionListener
{
private int mode = DESELECTION_AUTO;
private final ArrayList<AbstractButton> buttons = new ArrayList<AbstractButton>();
protected ToggleGroup() { /* empty */ }
protected void addToggleButton(AbstractButton button) {
button.addActionListener(this);
buttons.add(button);
}
// private void removeToggleButton( AbstractButton button )
// {
// button.removeActionListener( this );
// buttons.remove( button );
// }
protected void setGroupMode( int mode )
{
this.mode = mode;
}
public void actionPerformed( ActionEvent e )
{
AbstractButton button = (AbstractButton) e.getSource();
int i;
AbstractButton button2;
Action action = button.getAction();
boolean promote = true;
if( button.isSelected() ) {
for (i = 0; i < buttons.size(); i++) {
button2 = buttons.get(i);
if (button2 != button && button2.isSelected()) {
button2.setSelected(false);
}
}
} else {
if( (mode == DESELECTION_FORBIDDEN) ||
((mode == DESELECTION_AUTO) && (buttons.size() > 1)) ) {
button.setSelected( true );
}
promote = false;
}
if( promote && action != null && action instanceof ToolAction ) {
dispatchChange( button, (ToolAction) action );
}
}
}
}