package bibliothek.help;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.WindowConstants;
import bibliothek.demonstration.Monitor;
import bibliothek.demonstration.util.LookAndFeelMenu;
import bibliothek.gui.DockController;
import bibliothek.gui.DockFrontend;
import bibliothek.gui.DockStation;
import bibliothek.gui.DockTheme;
import bibliothek.gui.DockUI;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.FlapDockStation;
import bibliothek.gui.dock.ScreenDockStation;
import bibliothek.gui.dock.SplitDockStation;
import bibliothek.gui.dock.action.ActionGuard;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.station.split.SplitDockGrid;
import bibliothek.gui.dock.station.split.SplitDockProperty;
import bibliothek.gui.dock.station.support.PlaceholderStrategy;
import bibliothek.gui.dock.station.support.PlaceholderStrategyListener;
import bibliothek.gui.dock.support.lookandfeel.ComponentCollector;
import bibliothek.gui.dock.support.lookandfeel.LookAndFeelList;
import bibliothek.gui.dock.themes.ThemeFactory;
import bibliothek.gui.dock.themes.ThemeMeta;
import bibliothek.gui.dock.util.PropertyKey;
import bibliothek.help.control.LinkManager;
import bibliothek.help.control.URManager;
import bibliothek.help.control.actions.RedoDockAction;
import bibliothek.help.control.actions.UndoDockAction;
import bibliothek.help.model.HelpModel;
import bibliothek.help.util.ResourceSet;
import bibliothek.help.view.LayoutMenu;
import bibliothek.help.view.PanelMenu;
import bibliothek.help.view.SelectingView;
import bibliothek.help.view.TypeHierarchyView;
import bibliothek.help.view.dock.DockableButton;
import bibliothek.help.view.dock.Minimizer;
import bibliothek.util.Path;
/**
* This is the central point of the application. The core is responsible to
* startup and to shutdown the application. The core puts all elements
* together on startup, and frees resources on shutdown.
* @author Benjamin Sigg
*
*/
public class Core implements ComponentCollector{
/** whether this application runs in an secure environment or not */
private boolean secure;
/** monitor to inform when the state of this application changes */
private Monitor monitor;
/** main access to the docking framework */
private DockFrontend frontend;
/** dockable screen */
private ScreenDockStation screen;
/** central docking station */
private SplitDockStation station;
/** the applications main frame */
private JFrame frame;
/** whether the {@link DockTheme} currently is changing */
private boolean onThemeUpdate = false;
/**
* Creates a new core.
* @param secure whether the application should run in a restricted
* environment
* @param monitor observer to be informed when the application starts
* or shuts down, can be <code>null</code>
*/
public Core( boolean secure, Monitor monitor ){
this.secure = secure;
this.monitor = monitor;
}
/**
* Loads the model, creates the graphical user interface and shows it.
*/
public void startup(){
try{
JPanel dockbar = new JPanel( new FlowLayout( FlowLayout.LEADING ));
buildContent( dockbar );
HelpModel model = new HelpModel( "/data/bibliothek/help/help.data" );
LinkManager links = new LinkManager();
links.setModel( model );
URManager ur = links.getUR();
UndoDockAction actionUndo = new UndoDockAction( ur );
RedoDockAction actionRedo = new RedoDockAction( ur );
final DefaultDockActionSource actions = new DefaultDockActionSource( actionUndo, actionRedo );
frontend.getController().addActionGuard( new ActionGuard(){
public boolean react( Dockable dockable ){
return dockable.asDockStation() == null;
}
public DockActionSource getSource( Dockable dockable ){
return actions;
}
});
frontend.getController().getProperties().set( PropertyKey.DOCK_STATION_ICON, ResourceSet.ICONS.get( "application" ) );
frontend.getController().getProperties().set( PropertyKey.DOCK_STATION_TITLE, "Help" );
frontend.getController().getProperties().set( PlaceholderStrategy.PLACEHOLDER_STRATEGY, new PlaceholderStrategy(){
public void uninstall( DockStation station ){
// ignore
}
public void removeListener( PlaceholderStrategyListener listener ){
// ignore
}
public boolean isValidPlaceholder( Path placeholder ){
return true;
}
public void install( DockStation station ){
// ignore
}
public Path getPlaceholderFor( Dockable dockable ){
if( dockable instanceof SelectingView ){
return new Path( "selecting", dockable.getTitleText() );
}
return null;
}
public void addListener( PlaceholderStrategyListener listener ){
// ignore
}
});
SelectingView viewPackage = new SelectingView( links, "Packages", ResourceSet.ICONS.get( "package" ), "package-list" );
SelectingView viewClasses = new SelectingView( links, "Classes", ResourceSet.ICONS.get( "class" ), "class-list" );
SelectingView viewFields = new SelectingView( links, "Fields", ResourceSet.ICONS.get( "field" ), "field-list" );
SelectingView viewConstructors = new SelectingView( links, "Constructors", ResourceSet.ICONS.get( "constructor" ), "constructor-list" );
SelectingView viewMethods = new SelectingView( links, "Methods", ResourceSet.ICONS.get( "method" ), "method-list" );
SelectingView viewContent = new SelectingView( links, "Content", ResourceSet.ICONS.get( "content" ), "class",
"constructor-list", "constructor",
"field-list", "field",
"method-list", "method" );
TypeHierarchyView viewHierarchy = new TypeHierarchyView( links );
links.select( "package-list:root" );
buttonize( dockbar, viewPackage );
buttonize( dockbar, viewClasses );
buttonize( dockbar, viewFields );
buttonize( dockbar, viewConstructors );
buttonize( dockbar, viewMethods );
buttonize( dockbar, viewContent );
buttonize( dockbar, viewHierarchy );
frontend.addDockable( "packages", viewPackage );
frontend.addDockable( "classes", viewClasses );
frontend.addDockable( "fields", viewFields );
frontend.addDockable( "constructors", viewConstructors );
frontend.addDockable( "methods", viewMethods );
frontend.addDockable( "content", viewContent );
frontend.addDockable( "hierarchy", viewHierarchy );
SplitDockGrid grid = new SplitDockGrid( );
grid.addDockable( 0, 0, 1.5, 1, viewPackage );
grid.addDockable( 0, 1, 1.5, 2, viewClasses );
grid.addDockable( 0, 3, 1, 1, viewConstructors );
grid.addDockable( 1, 3, 1, 1, viewFields );
grid.addDockable( 2, 3, 1, 1, viewMethods );
grid.addDockable( 1, 0, 2, 3, viewContent );
grid.addDockable( 3, 0, 1, 3, viewHierarchy );
station.dropTree( grid.toTree() );
buildMenu();
frame.setVisible( true );
screen.setShowing( true );
}
catch( IOException ex ){
ex.printStackTrace();
}
finally{
if( monitor != null ){
monitor.publish( this );
monitor.running();
}
}
}
/**
* Closes the graphical user interface and frees resources. Exits the
* application if no {@link Monitor} was provided through the constructor.
*/
public void shutdown(){
frame.dispose();
screen.setShowing( false );
frontend.getController().kill();
if( monitor == null )
System.exit( 0 );
else
monitor.shutdown();
}
public Collection<Component> listComponents(){
List<Component> list = new ArrayList<Component>();
list.add( frame );
for( Dockable d : frontend.getController().getRegister().listDockables() )
list.add( d.getComponent() );
return list;
}
/**
* Creates the main frame and all {@link DockStation}s.
*/
private void buildContent( Container dockbar ){
FlapDockStation north, south, east, west;
frame = new JFrame();
frame.setTitle( "Help - Demonstration of DockingFrames" );
frame.setIconImage( ResourceSet.toImage( ResourceSet.ICONS.get( "application" ) ) );
DockController.disableCoreWarning();
frontend = new DockFrontend( frame );
frontend.getController().setRestrictedEnvironment( secure );
north = new FlapDockStation();
south = new FlapDockStation();
east = new FlapDockStation();
west = new FlapDockStation();
screen = new ScreenDockStation( frame );
station = new SplitDockStation();
frontend.setDefaultHideable( true );
Minimizer minimizer = new Minimizer( this, frontend.getController() );
minimizer.addAreaNormalized( station );
minimizer.addAreaNormalized( screen );
minimizer.setDefaultStation( station );
Container content = frame.getContentPane();
content.setLayout( new BorderLayout() );
content.add( dockbar, BorderLayout.NORTH );
Container center = new Container();
content.add( center, BorderLayout.CENTER );
center.setLayout( new BorderLayout() );
center.add( station, BorderLayout.CENTER );
center.add( south.getComponent(), BorderLayout.SOUTH );
center.add( north.getComponent(), BorderLayout.NORTH );
center.add( east.getComponent(), BorderLayout.EAST );
center.add( west.getComponent(), BorderLayout.WEST );
minimizer.addAreaMinimized( north, SplitDockProperty.NORTH );
minimizer.addAreaMinimized( south, SplitDockProperty.SOUTH );
minimizer.addAreaMinimized( east, SplitDockProperty.EAST );
minimizer.addAreaMinimized( west, SplitDockProperty.WEST );
frame.setBounds( 20, 20, 800, 600 );
frame.setTitle( "Help - Demonstration of DockingFrames" );
frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
frame.addWindowListener( new WindowAdapter(){
@Override
public void windowClosing( WindowEvent e ){
shutdown();
}
});
frontend.addRoot( "north", north );
frontend.addRoot( "south", south );
frontend.addRoot( "east", east );
frontend.addRoot( "west", west );
frontend.addRoot( "root", station );
frontend.addRoot( "screen", screen );
}
/**
* Creates a button in <code>dockbar</code> and connects the button with
* <code>dockable</code> and {@link #frontend}.
* @param dockbar the parent of the new button
* @param dockable the element for which to create the button
*/
private void buttonize( Container dockbar, Dockable dockable ){
DockableButton button = new DockableButton( frontend, dockable );
dockbar.add( button );
frontend.addRepresentative( button );
}
/**
* Builds the menubar and adds it to {@link #frame}
*/
private void buildMenu(){
JMenuBar menubar = new JMenuBar();
menubar.add( new PanelMenu( frontend ) );
menubar.add( new LayoutMenu( frontend ) );
JMenu themes = new JMenu( "Window" );
menubar.add( themes );
LookAndFeelList list;
if( monitor == null ){
list = LookAndFeelList.getDefaultList();
list.addComponentCollector( this );
}
else
list = monitor.getGlobalLookAndFeel();
themes.add( new LookAndFeelMenu( frame, list ) );
themes.add( createThemeMenu() );
// no preferences yet
// themes.add( new PreferenceItem( frame, frontend.getController() ));
frame.setJMenuBar( menubar );
}
/**
* Creates a menu that contains items to change the {@link DockTheme}.
* @return the newly created menu
*/
private JMenu createThemeMenu(){
JMenu dockTheme = new JMenu( "Theme" );
ButtonGroup group = new ButtonGroup();
boolean first = true;
for( final ThemeFactory factory : DockUI.getDefaultDockUI().getThemes()){
ThemeMeta meta = factory.createMeta( frontend.getController() );
JRadioButtonMenuItem item = new JRadioButtonMenuItem( meta.getName() );
if( first ){
item.setSelected( true );
frontend.getController().setTheme( factory.create( frontend.getController() ) );
first = false;
}
group.add( item );
item.setToolTipText( meta.getDescription() );
item.addActionListener( new ActionListener(){
public void actionPerformed( ActionEvent e ){
onThemeUpdate = true;
frontend.getController().setTheme( factory.create( frontend.getController() ) );
onThemeUpdate = false;
}
});
dockTheme.add( item );
}
return dockTheme;
}
/**
* Tells whether the {@link DockTheme} is currently exchanging or not.
* @return <code>true</code> if the application currently changes the
* theme
*/
public boolean isOnThemeUpdate(){
return onThemeUpdate;
}
}