/*
* 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.control;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.JDialog;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import bibliothek.gui.DockController;
import bibliothek.gui.DockTheme;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.control.focus.DefaultFocusRequest;
import bibliothek.gui.dock.focus.DockableSelection;
import bibliothek.gui.dock.focus.DockableSelectionListener;
import bibliothek.gui.dock.util.DockProperties;
import bibliothek.gui.dock.util.PropertyKey;
import bibliothek.gui.dock.util.PropertyValue;
/**
* A {@link DockableSelector} is able to open a popup when the user hits a special
* combination of keys. The popup uses a {@link DockableSelection} to present
* the user different {@link Dockable}s from which he can choose one to become focused.
* @author Benjamin Sigg
*/
public class DockableSelector {
/** key for the {@link DockProperties}, telling which {@link KeyStroke} activates the selection */
public static final PropertyKey<KeyStroke> INIT_SELECTION =
new PropertyKey<KeyStroke>( "dockable selector init selection keystroke" );
/** the currently active keystroke */
private PropertyValue<KeyStroke> initSelection = new PropertyValue<KeyStroke>( INIT_SELECTION ){
@Override
protected void valueChanged( KeyStroke oldValue, KeyStroke newValue ) {
// ignore
}
};
/** listens to keyboard and to {@link DockableSelection} */
private Listener listener = new Listener();
/** The currently observed controller */
private DockController controller;
/** the selection which is currently used */
private DockableSelection selection;
/** the dialog which shows the selection */
private JDialog dialog;
/**
* Sets the controller which should be observed.
* @param controller the currently observed controller
*/
public void setController( DockController controller ){
cancel();
if( this.controller != null ){
this.controller.getKeyboardController().removeGlobalListener( listener );
}
this.controller = controller;
initSelection.setProperties( controller );
if( this.controller != null ){
this.controller.getKeyboardController().addGlobalListener( listener );
}
}
/**
* Opens the popup window if possible and allows the user the choice between different
* {@link Dockable}s.
*/
public void select(){
if( !isOpen() ){
cancel();
open();
}
}
/**
* Tells whether the window is shown to the user right now.
* @return whether the window is visible
*/
public boolean isOpen(){
return selection != null && dialog != null && dialog.isVisible();
}
/**
* Closes the currently open popup window without changing the focused {@link Dockable}
*/
public void cancel(){
close();
}
/**
* Close the currently open popup window and changes the focused
* {@link Dockable} to <code>dockable</code>.
* @param dockable the element that will own the focus
*/
public void stop( Dockable dockable ){
close();
controller.setFocusedDockable( new DefaultFocusRequest( dockable, null, false ));
}
private void open(){
selection = controller.getProperties().get( DockTheme.DOCKABLE_SELECTION );
if( selection != null && selection.hasChoices( controller )){
Window root = controller.findRootWindow();
if( dialog == null || dialog.getOwner() != root ){
if( dialog != null )
dialog.dispose();
if( root instanceof Frame )
dialog = new JDialog( (Frame)root, false );
else if( root instanceof Dialog )
dialog = new JDialog( (Dialog)root, false );
else{
dialog = new JDialog();
dialog.setModal( false );
}
dialog.setDefaultCloseOperation( JDialog.DO_NOTHING_ON_CLOSE );
dialog.setUndecorated( true );
dialog.getRootPane().setWindowDecorationStyle( JRootPane.NONE );
dialog.setLayout( new BorderLayout() );
}
dialog.addWindowFocusListener( listener );
selection.open( controller );
final Component base = selection.getComponent();
dialog.add( base, BorderLayout.CENTER );
dialog.pack();
dialog.setLocationRelativeTo( root );
selection.addDockableSelectionListener( listener );
base.requestFocusInWindow();
dialog.setVisible( true );
}
else
selection = null;
}
private void close(){
if( dialog != null ){
if( selection != null ){
dialog.removeWindowFocusListener( listener );
selection.removeDockableSelectionListener( listener );
selection.close();
selection = null;
}
dialog.setVisible( false );
dialog.getContentPane().removeAll();
}
}
/**
* A listener that triggers the {@link DockableSelector} and that observes
* the active {@link DockableSelection}.
* @author Benjamin Sigg
*/
private class Listener implements KeyListener, DockableSelectionListener, WindowFocusListener{
public void keyPressed( KeyEvent event ) {
if( event.isConsumed() )
return;
if( KeyStroke.getKeyStrokeForEvent( event ).equals( initSelection.getValue() )){
select();
event.consume();
}
}
public void keyReleased( KeyEvent event ) {
if( event.isConsumed() )
return;
if( KeyStroke.getKeyStrokeForEvent( event ).equals( initSelection.getValue() )){
select();
event.consume();
}
}
public void keyTyped( KeyEvent event ) {
if( event.isConsumed() )
return;
if( KeyStroke.getKeyStrokeForEvent( event ).equals( initSelection.getValue() )){
select();
event.consume();
}
}
public void windowGainedFocus( WindowEvent e ) {
// ignore
}
public void windowLostFocus( WindowEvent e ) {
if( selection != null )
cancel();
}
public void canceled() {
cancel();
}
public void considering( Dockable dockable ) {
// ignore
}
public void selected( Dockable dockable ) {
stop( dockable );
}
}
}