/**
* Copyright (c) 2005-2017, KoLmafia development team
* http://kolmafia.sourceforge.net/
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* [1] Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* [2] Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* [3] Neither the name "KoLmafia" nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package net.sourceforge.kolmafia.swingui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import apple.dts.samplecode.osxadapter.OSXAdapter;
import net.java.dev.spellcast.utilities.DataUtilities;
import net.java.dev.spellcast.utilities.JComponentUtilities;
import net.sourceforge.kolmafia.CreateFrameRunnable;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.KoLConstants.MafiaState;
import net.sourceforge.kolmafia.KoLDesktop;
import net.sourceforge.kolmafia.KoLGUIConstants;
import net.sourceforge.kolmafia.KoLmafiaGUI;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.StaticEntity;
import net.sourceforge.kolmafia.listener.CharacterListener;
import net.sourceforge.kolmafia.listener.CharacterListenerRegistry;
import net.sourceforge.kolmafia.listener.Listener;
import net.sourceforge.kolmafia.listener.PreferenceListenerRegistry;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.session.LogoutManager;
import net.sourceforge.kolmafia.swingui.button.LoadScriptButton;
import net.sourceforge.kolmafia.swingui.listener.DefaultComponentFocusTraversalPolicy;
import net.sourceforge.kolmafia.swingui.listener.RefreshSessionListener;
import net.sourceforge.kolmafia.swingui.listener.WorldPeaceListener;
import net.sourceforge.kolmafia.swingui.menu.GlobalMenuBar;
import net.sourceforge.kolmafia.swingui.menu.ScriptMenu;
import net.sourceforge.kolmafia.swingui.panel.CompactSidePane;
import net.sourceforge.kolmafia.swingui.widget.GenericScrollPane;
import net.sourceforge.kolmafia.swingui.widget.RequestPane;
import net.sourceforge.kolmafia.utilities.InputFieldUtilities;
import net.sourceforge.kolmafia.utilities.LockableListFactory;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public abstract class GenericFrame
extends JFrame
implements Runnable, FocusListener
{
private static int existingFrameCount = 0;
private boolean packedOnce = false;
private boolean exists = true;
private HashMap listenerMap;
private GlobalMenuBar menuBar;
private FramePanel framePanel;
public JTabbedPane tabs;
protected String lastTitle;
protected String frameName;
public CompactSidePane sidepane = null;
public CharacterListener refreshListener = null;
static
{
GenericFrame.compileScripts();
GenericFrame.compileBookmarks();
}
/**
* Constructs a new <code>KoLFrame</code> with the given title, to be associated with the given
* StaticEntity.getClient().
*/
public GenericFrame()
{
this( "" );
}
/**
* Constructs a new <code>KoLFrame</code> with the given title, to be associated with the given
* StaticEntity.getClient().
*/
public GenericFrame( final String title )
{
this.setTitle( title );
this.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
this.tabs = this.getTabbedPane();
this.framePanel = new FramePanel();
this.frameName = this.getClass().getName();
this.frameName = this.frameName.substring( this.frameName.lastIndexOf( "." ) + 1 );
if ( this.shouldAddStatusBar() )
{
JScrollPane statusBar = KoLConstants.commandBuffer.addDisplay( new RequestPane() );
JComponentUtilities.setComponentSize( statusBar, new Dimension( 200, 50 ) );
JSplitPane doublePane =
new JSplitPane( JSplitPane.VERTICAL_SPLIT, new GenericScrollPane( framePanel ), statusBar );
doublePane.setOneTouchExpandable( true );
doublePane.setDividerLocation( 0.9 );
JPanel wrappedDoublePane = new JPanel( new BorderLayout( 0, 0 ) );
wrappedDoublePane.add( doublePane, BorderLayout.CENTER );
this.setContentPane( wrappedDoublePane );
}
else
{
this.setContentPane( framePanel );
}
this.menuBar = new GlobalMenuBar();
this.setJMenuBar( this.menuBar );
this.addHotKeys();
++GenericFrame.existingFrameCount;
if ( this.showInWindowMenu() )
{
KoLGUIConstants.existingFrames.add( this.getFrameName() );
}
this.setFocusCycleRoot( true );
this.setFocusTraversalPolicy( new DefaultComponentFocusTraversalPolicy( this.framePanel ) );
this.addFocusListener( this );
OSXAdapter.setWindowCanFullScreen( this, true );
}
public void focusGained( FocusEvent e )
{
this.framePanel.requestFocus();
}
public void focusLost( FocusEvent e )
{
}
public void setCenterComponent( Component c )
{
this.framePanel.add( c, BorderLayout.CENTER );
}
public Component getCenterComponent()
{
return this.framePanel.centerComponent;
}
public void removeCenterComponent()
{
this.framePanel.remove( this.framePanel.centerComponent );
}
public JPanel getFramePanel()
{
return this.framePanel;
}
public boolean shouldAddStatusBar()
{
return Preferences.getBoolean( "addStatusBarToFrames" ) && !this.appearsInTab();
}
public boolean showInWindowMenu()
{
return true;
}
protected void addActionListener( final JCheckBox component, final ActionListener listener )
{
if ( this.listenerMap == null )
{
this.listenerMap = new HashMap();
}
component.addActionListener( listener );
this.listenerMap.put( component, new WeakReference( listener ) );
}
protected void addActionListener( final JComboBox component, final ActionListener listener )
{
if ( this.listenerMap == null )
{
this.listenerMap = new HashMap();
}
component.addActionListener( listener );
this.listenerMap.put( component, new WeakReference( listener ) );
}
protected void removeActionListener( final JComponent component, final ActionListener listener )
{
if ( component instanceof JCheckBox )
{
( (JCheckBox) component ).removeActionListener( listener );
}
if ( component instanceof JComboBox )
{
( (JComboBox) component ).removeActionListener( listener );
}
}
public boolean appearsInTab()
{
return GenericFrame.appearsInTab( this.frameName );
}
public static boolean appearsInTab( String frameName )
{
String tabSetting = Preferences.getString( "initialDesktop" );
return tabSetting.indexOf( frameName ) != -1;
}
public JTabbedPane getTabbedPane()
{
return KoLmafiaGUI.getTabbedPane();
}
public void addHotKeys()
{
JComponentUtilities.addGlobalHotKey( this.getRootPane(), KeyEvent.VK_ESCAPE, new WorldPeaceListener() );
JComponentUtilities.addGlobalHotKey( this.getRootPane(), KeyEvent.VK_F5, new RefreshSessionListener() );
JComponentUtilities.addGlobalHotKey(
this.getRootPane(), KeyEvent.VK_PAGE_UP, InputEvent.CTRL_MASK, new TabForwardListener() );
JComponentUtilities.addGlobalHotKey(
this.getRootPane(), KeyEvent.VK_PAGE_DOWN, InputEvent.CTRL_MASK, new TabBackwardListener() );
}
public void removeHotKeys()
{
this.getRootPane().unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ) );
this.getRootPane().unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_F5, 0 ) );
this.getRootPane().unregisterKeyboardAction(
KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_UP, InputEvent.CTRL_MASK ) );
this.getRootPane().unregisterKeyboardAction(
KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_DOWN, InputEvent.CTRL_MASK ) );
}
private class TabForwardListener
implements ActionListener
{
public void actionPerformed( final ActionEvent e )
{
if ( GenericFrame.this.tabs == null )
{
return;
}
GenericFrame.this.tabs.setSelectedIndex( ( GenericFrame.this.tabs.getSelectedIndex() + 1 ) % GenericFrame.this.tabs.getTabCount() );
}
}
private class TabBackwardListener
implements ActionListener
{
public void actionPerformed( final ActionEvent e )
{
if ( GenericFrame.this.tabs == null )
{
return;
}
GenericFrame.this.tabs.setSelectedIndex( GenericFrame.this.tabs.getSelectedIndex() == 0 ? GenericFrame.this.tabs.getTabCount() - 1 : GenericFrame.this.tabs.getSelectedIndex() - 1 );
}
}
public final void addTab( final String name, final JComponent panel )
{
if ( this.tabs == null )
{
return;
}
this.tabs.setOpaque( true );
GenericScrollPane scroller = new GenericScrollPane( panel );
JComponentUtilities.setComponentSize( scroller, 560, 400 );
this.tabs.add( name, scroller );
}
@Override
public final void setTitle( final String newTitle )
{
this.lastTitle = newTitle;
KoLDesktop.setTitle( this, newTitle );
if ( this instanceof LoginFrame )
{
super.setTitle( this.lastTitle );
return;
}
String username = KoLCharacter.getUserName();
if ( username.equals( "" ) )
{
username = "Not Logged In";
}
super.setTitle( this.lastTitle + " (" + username + ")" );
}
public boolean useSidePane()
{
return false;
}
public JToolBar getToolbar()
{
return this.getToolbar( false );
}
public JToolBar getToolbar( final boolean force )
{
JToolBar toolbarPanel = null;
if ( force )
{
toolbarPanel = new JToolBar( "KoLmafia Toolbar" );
this.framePanel.add( toolbarPanel, BorderLayout.NORTH );
toolbarPanel.setFloatable( false );
return toolbarPanel;
}
switch ( Preferences.getInteger( "toolbarPosition" ) )
{
case 1:
toolbarPanel = new JToolBar( "KoLmafia Toolbar" );
this.framePanel.add( toolbarPanel, BorderLayout.NORTH );
break;
case 2:
toolbarPanel = new JToolBar( "KoLmafia Toolbar" );
this.framePanel.add( toolbarPanel, BorderLayout.SOUTH );
break;
case 3:
toolbarPanel = new JToolBar( "KoLmafia Toolbar", JToolBar.VERTICAL );
this.framePanel.add( toolbarPanel, BorderLayout.WEST );
break;
case 4:
toolbarPanel = new JToolBar( "KoLmafia Toolbar", JToolBar.VERTICAL );
this.framePanel.add( toolbarPanel, BorderLayout.EAST );
break;
default:
toolbarPanel = new JToolBar( "KoLmafia Toolbar" );
if ( this instanceof LoginFrame || this instanceof ChatFrame )
{
this.framePanel.add( toolbarPanel, BorderLayout.NORTH );
break;
}
}
if ( toolbarPanel != null )
{
toolbarPanel.setFloatable( false );
}
return toolbarPanel;
}
/**
* Overrides the default behavior of dispose so that the frames are removed from the internal list of existing
* frames. Also allows for automatic exit.
*/
@Override
public void dispose()
{
StaticEntity.unregisterPanels( this );
if ( this.isVisible() )
{
this.rememberPosition();
this.setVisible( false );
}
// Determine which frame needs to be removed from
// the maintained list of frames.
if ( this.exists )
{
this.exists = false;
--GenericFrame.existingFrameCount;
KoLGUIConstants.existingFrames.remove( this.getFrameName() );
}
// Remove listeners from interface elements
this.removeHotKeys();
if ( this.listenerMap != null )
{
Object[] entries = this.listenerMap.entrySet().toArray();
for ( int i = 0; i < entries.length; ++i )
{
Entry entry = (Entry) entries[ i ];
JComponent component = (JComponent) entry.getKey();
WeakReference reference = (WeakReference) entry.getValue();
ActionListener listener = (ActionListener) reference.get();
if ( listener != null )
{
this.removeActionListener( component, listener );
}
}
}
if ( this.refreshListener != null )
{
CharacterListenerRegistry.removeCharacterListener( this.refreshListener );
}
this.menuBar.dispose();
super.dispose();
this.checkForLogout();
}
public boolean exists()
{
return this.exists;
}
public static boolean instanceExists()
{
return GenericFrame.existingFrameCount != 0;
}
protected void checkForLogout()
{
if ( StaticEntity.isGUIRequired() && !GenericFrame.instanceExists() )
{
RequestThread.runInParallel( new LogoutRunnable() );
}
}
@Override
public String toString()
{
return this.lastTitle;
}
public String getLastTitle()
{
return this.lastTitle;
}
public String getFrameName()
{
return this.frameName;
}
/**
* Method which adds a compact pane to the west side of the component. Note that this method can only be used if the
* KoLFrame on which it is called has not yet added any components. If there are any added components, this method
* will do nothing.
*/
public void addCompactPane()
{
if ( this.sidepane != null )
{
return;
}
this.sidepane = new CompactSidePane();
this.sidepane.run();
this.refreshListener = new CharacterListener( this.sidepane );
CharacterListenerRegistry.addCharacterListener( this.refreshListener );
this.sidepane.setBackground( KoLGUIConstants.ENABLED_COLOR );
this.framePanel.add( this.sidepane, BorderLayout.WEST );
}
public void addScriptPane()
{
int scriptButtonPosition = Preferences.getInteger( "scriptButtonPosition" );
String scriptList = Preferences.getString( "scriptList" ).trim();
// Scripts are added to a new panel on right
// You are allowed to have zero buttons in it.
ScriptBar scriptBar = new ScriptBar( scriptList, scriptButtonPosition );
this.framePanel.add( scriptBar, BorderLayout.EAST );
}
private class ScriptBar
extends JToolBar
implements Listener
{
private String scriptList = "";
private boolean showScriptList = false;
public ScriptBar( final String scriptList, final int scriptButtonPosition )
{
super( SwingConstants.VERTICAL );
this.setFloatable( false );
PreferenceListenerRegistry.registerPreferenceListener( "scriptList", this );
PreferenceListenerRegistry.registerPreferenceListener( "scriptButtonPosition", this );
this.update( scriptList, scriptButtonPosition );
}
public void update()
{
this.update( Preferences.getString( "scriptList" ), Preferences.getInteger( "scriptButtonPosition" ) );
}
public void update( String scriptList, final int scriptButtonPosition )
{
scriptList = scriptList.trim();
if ( scriptButtonPosition == 0 )
{
// We are not showing script buttons
if ( !this.scriptList.equals( "" ) )
{
this.removeAll();
this.revalidate();
this.repaint();
}
this.scriptList = scriptList;
this.showScriptList = false;
return;
}
// We are showing scripts. If we previously were and
// they have not changed, nothing to do.
if ( this.showScriptList && this.scriptList.equals( scriptList ) )
{
return;
}
// We are showing scripts when we were not before, or
// scripts have changed. Update buttons.
// Remove all current script buttons
this.removeAll();
// Create new script buttons for current script list
String[] scripts = scriptList.split( " +\\| +" );
int index = 1;
for ( String script : scripts )
{
if ( !script.equals( "" ) )
{
this.add( new LoadScriptButton( index++, script ) );
}
}
this.revalidate();
this.repaint();
// Save current scriptList
this.showScriptList = true;
this.scriptList = scriptList;
}
}
public void setStatusMessage( final String message )
{
}
public void updateDisplayState( final MafiaState displayState )
{
// Change the background of the frame based on
// the current display state -- but only if the
// compact pane has already been constructed.
Color color;
boolean enabled;
switch ( displayState )
{
case ABORT:
case ERROR:
color = KoLGUIConstants.ERROR_COLOR;
enabled = true;
break;
case ENABLE:
color = KoLGUIConstants.ENABLED_COLOR;
enabled = true;
break;
default:
color = KoLGUIConstants.DISABLED_COLOR;
enabled = false;
break;
}
if ( this.sidepane != null )
{
this.sidepane.setBackground( color );
}
this.setEnabled( enabled );
}
/**
* Overrides the default isEnabled() method, because the setEnabled() method does not call the superclass's version.
*
* @return <code>true</code>
*/
@Override
public final boolean isEnabled()
{
return true;
}
@Override
public void setEnabled( final boolean isEnabled )
{
}
@Override
public void processWindowEvent( final WindowEvent e )
{
if ( this.isVisible() && e.getID() == WindowEvent.WINDOW_CLOSING )
{
this.rememberPosition();
}
super.processWindowEvent( e );
if ( e.getID() == WindowEvent.WINDOW_ACTIVATED )
{
InputFieldUtilities.setActiveWindow( this );
}
}
@Override
public void setVisible( final boolean isVisible )
{
if ( isVisible )
{
this.restorePosition();
}
else
{
this.rememberPosition();
}
if ( !isVisible )
{
super.setVisible( false );
return;
}
try
{
if ( SwingUtilities.isEventDispatchThread() )
{
this.run();
}
else
{
SwingUtilities.invokeAndWait( this );
}
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
}
public void run()
{
super.setVisible( true );
super.setExtendedState( Frame.NORMAL );
super.repaint();
}
@Override
public void pack()
{
if ( !( this instanceof ChatFrame ) && !packedOnce )
{
super.pack();
packedOnce = true;
}
}
private void rememberPosition()
{
Point p = this.getLocation();
if ( this.tabs == null )
{
Preferences.setString( this.frameName, (int) p.getX() + "," + (int) p.getY() );
}
else
{
Preferences.setString(
this.frameName, (int) p.getX() + "," + (int) p.getY() + "," + this.tabs.getSelectedIndex() );
}
}
private void restorePosition()
{
int xLocation = 0;
int yLocation = 0;
Rectangle display = new Rectangle();
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
for (int j = 0; j < gs.length; j++) {
GraphicsDevice gd = gs[j];
GraphicsConfiguration[] gc = gd.getConfigurations();
for (int i = 0; i < gc.length; i++) {
display = display.union(gc[i].getBounds());
}
}
String position = Preferences.getString( this.frameName );
if ( position == null || position.indexOf( "," ) == -1 )
{
this.setLocationRelativeTo( null );
if ( !( this instanceof OptionsFrame ) && !( this instanceof KoLDesktop ) && this.tabs != null && this.tabs.getTabCount() > 0 )
{
this.tabs.setSelectedIndex( 0 );
}
return;
}
String[] location = position.split( "," );
xLocation = StringUtilities.parseInt( location[ 0 ] );
yLocation = StringUtilities.parseInt( location[ 1 ] );
if ( xLocation > display.x && yLocation > display.y && xLocation < ( display.x + display.width ) && yLocation < ( display.y + display.height ) )
{
this.setLocation( xLocation, yLocation );
}
else
{
this.setLocationRelativeTo( null );
}
if ( location.length > 2 && this.tabs != null )
{
int tabIndex = StringUtilities.parseInt( location[ 2 ] );
if ( tabIndex >= 0 && tabIndex < this.tabs.getTabCount() )
{
this.tabs.setSelectedIndex( tabIndex );
}
else if ( this.tabs.getTabCount() > 0 )
{
this.tabs.setSelectedIndex( 0 );
}
}
}
public static final void createDisplay( final Class frameClass )
{
KoLmafiaGUI.constructFrame( frameClass );
}
public static final void createDisplay( final Class frameClass, final Object[] parameters )
{
CreateFrameRunnable creator = new CreateFrameRunnable( frameClass, parameters );
creator.run();
}
public static final void compileScripts()
{
GenericFrame.compileScripts( Preferences.getInteger( "scriptMRULength" ) > 0 );
}
public static final void compileScripts( final boolean useMRUlist )
{
KoLConstants.scripts.clear();
// Get the list of files in the current directory or build from MRU
File [] scriptList = useMRUlist ?
KoLConstants.scriptMList.listAsFiles() :
DataUtilities.listFiles( KoLConstants.SCRIPT_LOCATION );
// Iterate through the files. Do this in two
// passes to make sure that directories start
// up top, followed by non-directories.
int directoryIndex = 0;
for ( int i = 0; i < scriptList.length; ++i )
{
if ( !ScriptMenu.shouldAddScript( scriptList[ i ] ) )
{
}
else if ( scriptList[ i ].isDirectory() )
{
KoLConstants.scripts.add( directoryIndex++ , scriptList[ i ] );
}
else
{
KoLConstants.scripts.add( scriptList[ i ] );
}
}
}
/**
* Utility method to save the entire list of bookmarks to the settings file. This should be called after every
* update.
*/
public static final void saveBookmarks()
{
StringBuilder bookmarkData = new StringBuilder();
for ( int i = 0; i < LockableListFactory.getsize( KoLConstants.bookmarks ); ++i )
{
if ( i > 0 )
{
bookmarkData.append( '|' );
}
bookmarkData.append( (String) LockableListFactory.getElementAt( KoLConstants.bookmarks, i ) );
}
Preferences.setString( "browserBookmarks", bookmarkData.toString() );
}
/**
* Utility method to compile the list of bookmarks based on the current settings.
*/
public static final void compileBookmarks()
{
KoLConstants.bookmarks.clear();
String[] bookmarkData = Preferences.getString( "browserBookmarks" ).split( "\\|" );
if ( bookmarkData.length > 1 )
{
for ( int i = 0; i < bookmarkData.length; ++i )
{
KoLConstants.bookmarks.add( bookmarkData[ i ] + "|" + bookmarkData[ ++i ] + "|" + bookmarkData[ ++i ] );
}
}
}
private static class FramePanel
extends JPanel
implements FocusListener
{
private Component centerComponent;
public FramePanel()
{
super( new BorderLayout() );
this.addFocusListener( this );
}
@Override
public void add( Component c, Object constraint )
{
super.add( c, constraint );
if ( constraint == BorderLayout.CENTER )
{
this.centerComponent = c;
this.setFocusCycleRoot( true );
this.setFocusTraversalPolicy( new DefaultComponentFocusTraversalPolicy( c ) );
}
}
public void focusGained( FocusEvent e )
{
if ( this.centerComponent != null )
{
this.centerComponent.requestFocus();
}
}
public void focusLost( FocusEvent e )
{
}
}
private static class LogoutRunnable
implements Runnable
{
public void run()
{
LogoutManager.logout();
}
}
}