/*
* 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) 2012 Herve Guillaume, 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
*
* Herve Guillaume
* rvguillaume@hotmail.com
* FR - France
*
* Benjamin Sigg
* benjamin_sigg@gmx.ch
* CH - Switzerland
*/
package bibliothek.gui.dock.station.toolbar.menu;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JToggleButton;
import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.util.icon.DockIcon;
/**
* The {@link CustomizationToolbarButton} is a button that allows to add one
* {@link Dockable} to a {@link DockStation}. This button also offers an
* indication telling whether the {@link Dockable} is already shown on another
* station.
*
* @author Benjamin Sigg
*/
public abstract class CustomizationToolbarButton implements
CustomizationMenuContent{
/**
* The different locations where a {@link Dockable} can be in respect to
* this button
*/
public static enum ItemLocation{
/** The {@link Dockable} is not visible anywhere */
INVISIBLE,
/**
* The {@link Dockable} is visible, but it is part of another
* {@link DockStation}
*/
ELSEWHERE,
/**
* The {@link Dockable} is visible and it is part of this
* {@link DockStation}
*/
HERE
}
private DockController controller;
private Icon icon;
private String description;
private String text;
private JLayeredPane base;
private JToggleButton button;
private JLabel elsewhere;
private CustomizationMenuCallback callback;
/** the icon of {@link #here} */
private DockIcon elsewhereIcon = new DockIcon(
"toolbar.customization.check", DockIcon.KIND_ICON){
@Override
protected void changed( Icon oldValue, Icon newValue ){
if (elsewhere != null){
elsewhere.setIcon(newValue);
}
}
};
@Override
public void setController( DockController controller ){
this.controller = controller;
if (callback != null){
elsewhereIcon.setController(controller);
}
}
@Override
public Component getView(){
return base;
}
@Override
public void bind( CustomizationMenuCallback callback ){
this.callback = callback;
button = new JToggleButton();
button.setIcon(icon);
button.setToolTipText(description);
button.setText(text);
button.setOpaque(false);
elsewhere = new JLabel();
elsewhereIcon.setController(controller);
elsewhere.setIcon(elsewhereIcon.value());
elsewhere.setVisible(false);
base = new JLayeredPane();
base.add(button);
base.add(elsewhere);
base.setLayer(button, JLayeredPane.DEFAULT_LAYER);
base.setLayer(elsewhere, JLayeredPane.MODAL_LAYER);
base.setLayout(new LayoutManager(){
@Override
public void removeLayoutComponent( Component comp ){
// ignore
}
@Override
public Dimension preferredLayoutSize( Container parent ){
return new Dimension(button.getPreferredSize().width
+ elsewhere.getPreferredSize().width + 1, button
.getPreferredSize().height);
}
@Override
public Dimension minimumLayoutSize( Container parent ){
return button.getMinimumSize();
}
@Override
public void layoutContainer( Container parent ){
if (parent.getComponentCount() == 2){
int width = parent.getWidth();
int height = parent.getHeight();
Dimension preferred = elsewhere.getPreferredSize();
int labelWidth = Math.min(preferred.width, width - 1);
int labelHeight = Math.min(preferred.height, height - 1);
button.setBounds(labelWidth + 2, 0, width - labelWidth - 2, height);
elsewhere.setBounds(1, 0, labelWidth,
labelHeight);
}
}
@Override
public void addLayoutComponent( String name, Component comp ){
// ignore
}
});
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed( ActionEvent e ){
ItemLocation location = getItemLocation();
setItemVisible(location != ItemLocation.HERE);
}
});
select();
}
private void select(){
ItemLocation location = getItemLocation();
elsewhere.setVisible(location == ItemLocation.HERE || location == ItemLocation.ELSEWHERE);
button.setSelected(location == ItemLocation.HERE);
}
/**
* Gets the current location of the {@link Dockable} that is described by
* this button.
*
* @return the current location
* @throws IllegalStateException
* if {@link #bind(CustomizationMenuCallback)} was not called
*/
protected ItemLocation getItemLocation(){
if (callback == null){
throw new IllegalStateException(
"this information is only available if the button has been bound");
}
if (!hasDockable()){
return ItemLocation.INVISIBLE;
}
Dockable item = getDockable();
DockStation parent = item.getDockParent();
if (parent == null){
return ItemLocation.INVISIBLE;
}
DockStation owner = callback.getOwner();
while (parent != null){
if (parent == owner){
return ItemLocation.HERE;
}
item = parent.asDockable();
if (item == null){
parent = null;
} else{
parent = item.getDockParent();
}
}
return ItemLocation.ELSEWHERE;
}
/**
* Removes the {@link Dockable} from its current parent and maybe appends it
* to the owner of this button.
*
* @param visible
* whether the item should be visible or not
*/
protected void setItemVisible( boolean visible ){
Dockable item = getDockable();
DockStation parent = item.getDockParent();
if (parent != null){
parent.drag(item);
}
if (visible){
CustomizationToolbarButton.this.callback.append(item);
}
select();
}
@Override
public void unbind(){
base = null;
button = null;
elsewhere = null;
elsewhereIcon.setController(null);
}
/**
* Sets the icon which should be shown on the button.
*
* @param icon
* the new icon, can be <code>null</code>
*/
public void setIcon( Icon icon ){
this.icon = icon;
if (button != null){
button.setIcon(icon);
}
}
/**
* Sets the text which should be shown on the button.
*
* @param icon
* the new text, can be <code>null</code>
*/
public void setText( String text){
this.text = text;
if (button != null){
button.setText(text);
}
}
/**
* Sets a text which describes the meaning of the button.
*
* @param description
* the description, can be <code>null</code>
*/
public void setDescription( String description ){
this.description = description;
if (button != null){
button.setToolTipText(description);
}
}
/**
* Tells whether the {@link Dockable} of this button, accessible by calling
* {@link #getDockable()}, is already present. If the item is not yet
* present, then it cannot be visible or selected at this time.
*
* @return whether the {@link Dockable} already exists
*/
protected abstract boolean hasDockable();
/**
* Gets the element that is put onto a toolbar. This method may create the
* {@link Dockable} lazily in the very moment it is used the first time.
*
* @return the item to show on the toolbar
*/
protected abstract Dockable getDockable();
}