/**
* 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.panel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.text.JTextComponent;
import net.java.dev.spellcast.utilities.ActionVerifyPanel;
import net.java.dev.spellcast.utilities.JComponentUtilities;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.StaticEntity;
import net.sourceforge.kolmafia.swingui.listener.ThreadedListener;
import net.sourceforge.kolmafia.swingui.widget.AutoFilterComboBox;
import net.sourceforge.kolmafia.swingui.widget.CollapsibleTextArea;
import net.sourceforge.kolmafia.utilities.InputFieldUtilities;
public abstract class GenericPanel
extends ActionVerifyPanel
{
protected ConfirmedListener CONFIRM_LISTENER = new ConfirmedListener();
protected CancelledListener CANCEL_LISTENER = new CancelledListener();
protected HashMap listenerMap;
public JPanel southContainer;
public JPanel actionStatusPanel;
public StatusLabel actionStatusLabel;
public GenericPanel()
{
super();
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final Dimension left, final Dimension right )
{
super( left, right );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final Dimension left, final Dimension right, final boolean isCenterPanel )
{
super( left, right, isCenterPanel );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText )
{
super( confirmedText );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final boolean isCenterPanel )
{
super( confirmedText, isCenterPanel );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final String cancelledText )
{
super( confirmedText, cancelledText );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final String cancelledText, final boolean isCenterPanel )
{
super( confirmedText, cancelledText, isCenterPanel );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final Dimension left, final Dimension right,
final boolean isCenterPanel )
{
super( confirmedText, left, right, isCenterPanel );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final String cancelledText1, final String cancelledText2 )
{
super( confirmedText, cancelledText1, cancelledText2 );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final String cancelledText, final Dimension left, final Dimension right )
{
super( confirmedText, cancelledText, left, right );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final String cancelledText1, final String cancelledText2,
final Dimension left, final Dimension right )
{
super( confirmedText, cancelledText1, cancelledText2, left, right );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final String cancelledText, final Dimension left,
final Dimension right, final boolean isCenterPanel )
{
super( confirmedText, cancelledText, left, right, isCenterPanel );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
public GenericPanel( final String confirmedText, final String cancelledText1, final String cancelledText2,
final Dimension left, final Dimension right, final boolean isCenterPanel )
{
super( confirmedText, cancelledText1, cancelledText2, left, right, isCenterPanel );
this.setListeners( CONFIRM_LISTENER, CANCEL_LISTENER );
StaticEntity.registerPanel( this );
}
@Override
public void setContent( final VerifiableElement[] elements, final boolean bothDisabledOnClick )
{
super.setContent( elements, bothDisabledOnClick );
// In addition to setting the content on these, also
// add a return-key listener to each of the input fields.
this.elements = elements;
this.addListeners();
this.addStatusLabel();
}
public void addListeners()
{
if ( this.elements == null )
{
return;
}
ActionConfirmListener listener = new ActionConfirmListener();
for ( int i = 0; i < this.elements.length; ++i )
{
this.addListener( this.elements[ i ].getInputField(), listener );
}
}
private void addListener( final Object component, final ActionConfirmListener listener )
{
if ( this.listenerMap == null )
{
this.listenerMap = new HashMap();
}
if ( component instanceof JTextField )
{
( (JTextField) component ).addKeyListener( listener );
this.listenerMap.put( component, new WeakReference( listener ) );
}
if ( component instanceof AutoFilterComboBox )
{
JTextComponent editor = (JTextComponent) ( (AutoFilterComboBox) component ).getEditor().getEditorComponent();
editor.addKeyListener( listener );
this.listenerMap.put( editor, new WeakReference( listener ) );
}
else if ( component instanceof JComboBox && ((JComboBox) component).isEditable() )
{
JTextComponent editor = (JTextComponent) ( (JComboBox) component ).getEditor().getEditorComponent();
editor.addKeyListener( listener );
this.listenerMap.put( editor, new WeakReference( listener ) );
}
}
@Override
public void dispose()
{
if ( this.listenerMap == null )
{
super.dispose();
return;
}
Object[] keys = this.listenerMap.keySet().toArray();
for ( int i = 0; i < keys.length; ++i )
{
WeakReference ref = (WeakReference) this.listenerMap.get( keys[ i ] );
if ( ref == null )
{
continue;
}
Object listener = ref.get();
if ( listener == null )
{
continue;
}
this.removeListener( keys[ i ], (ActionConfirmListener) listener );
}
this.listenerMap.clear();
this.listenerMap = null;
this.southContainer = null;
this.actionStatusPanel = null;
this.actionStatusLabel = null;
super.dispose();
}
private void removeListener( final Object component, final ActionConfirmListener listener )
{
if ( component instanceof JTextField )
{
( (JTextField) component ).removeKeyListener( listener );
}
if ( component instanceof AutoFilterComboBox )
{
JTextComponent editor = (JTextComponent) ( (AutoFilterComboBox) component ).getEditor().getEditorComponent();
editor.removeKeyListener( listener );
}
else if ( component instanceof JComboBox && ((JComboBox) component).isEditable() )
{
JTextComponent editor = (JTextComponent) ( (JComboBox) component ).getEditor().getEditorComponent();
editor.removeKeyListener( listener );
}
}
@Override
public void setEnabled( final boolean isEnabled )
{
super.setEnabled( isEnabled );
if ( this.elements == null || this.elements.length == 0 )
{
return;
}
for ( int i = 0; i < this.elements.length; ++i )
{
if ( this.elements[ i ] == null )
{
continue;
}
JComponent inputField = this.elements[ i ].getInputField();
if ( inputField == null )
{
continue;
}
inputField.setEnabled( isEnabled );
}
}
public void setStatusMessage( final String message )
{
if ( this.actionStatusLabel != null )
{
this.actionStatusLabel.setStatusMessage( message );
}
}
public void addStatusLabel()
{
if ( !this.shouldAddStatusLabel() )
{
return;
}
JPanel statusContainer = new JPanel();
statusContainer.setLayout( new BoxLayout( statusContainer, BoxLayout.Y_AXIS ) );
this.actionStatusPanel = new JPanel( new BorderLayout() );
this.actionStatusLabel = new StatusLabel();
this.actionStatusPanel.add( this.actionStatusLabel, BorderLayout.SOUTH );
statusContainer.add( this.actionStatusPanel );
statusContainer.add( Box.createVerticalStrut( 20 ) );
this.southContainer = new JPanel( new BorderLayout() );
this.southContainer.add( statusContainer, BorderLayout.NORTH );
this.container.add( this.southContainer, BorderLayout.SOUTH );
}
public boolean shouldAddStatusLabel()
{
if ( this.elements == null )
{
return false;
}
boolean shouldAddStatusLabel = this.elements != null && this.elements.length != 0;
for ( int i = 0; shouldAddStatusLabel && i < this.elements.length; ++i )
{
shouldAddStatusLabel &= !( this.elements[ i ].getInputField() instanceof JScrollPane );
}
return shouldAddStatusLabel;
}
private class StatusLabel
extends JLabel
{
public StatusLabel()
{
super( " ", SwingConstants.CENTER );
}
public void setStatusMessage( final String message )
{
String label = this.getText();
// If the current text or the string you're using is
// null, then do nothing.
if ( message == null || label == null || message.length() == 0 )
{
return;
}
// If the string which you're trying to set is blank,
// then you don't have to update the status message.
this.setText( message );
}
}
/**
* This internal class is used to process the request for selecting a
* file using the file dialog.
*/
public class ScriptSelectPanel
extends FileSelectPanel
{
public ScriptSelectPanel( final JComponent textField )
{
super( textField, true );
this.setPath( KoLConstants.SCRIPT_LOCATION );
}
}
public class FileSelectPanel
extends JPanel
implements ActionListener, FocusListener
{
private final JTextComponent textField;
private final JButton fileButton;
private File path = null;
private JLabel label;
public FileSelectPanel( final JComponent textField, final boolean button )
{
this.setLayout( new BorderLayout( 0, 0 ) );
if ( textField instanceof JTextComponent )
{
this.textField = (JTextComponent) textField;
}
else if ( textField instanceof CollapsibleTextArea )
{
this.textField = ( (CollapsibleTextArea) textField ).getArea();
this.label = ( (CollapsibleTextArea) textField ).getLabel();
}
else
{
this.textField = new JTextField();
}
this.textField.addFocusListener( this );
this.add( textField, BorderLayout.CENTER );
if ( button )
{
this.fileButton = new JButton( "..." );
JComponentUtilities.setComponentSize( this.fileButton, 20, 20 );
this.fileButton.addActionListener( this );
this.add( this.fileButton, BorderLayout.EAST );
}
else
{
this.fileButton = null;
}
}
@Override
public void setEnabled( final boolean isEnabled )
{
this.textField.setEnabled( isEnabled );
if ( this.fileButton != null )
{
this.fileButton.setEnabled( isEnabled );
}
}
public void setPath( final File path )
{
this.path = path;
}
public String getText()
{
return this.textField.getText();
}
public void setText( String text )
{
try
{
text = this.getRelativePath( text );
}
catch ( IOException e )
{
}
this.textField.setText( text );
}
private String getRelativePath( final String text )
throws IOException
{
File root = KoLConstants.ROOT_LOCATION;
String rootPath = root.getCanonicalPath();
if ( rootPath.endsWith( File.separator ) )
{
rootPath = rootPath.substring( 0, rootPath.length() - 1 );
}
if ( rootPath.equals( "" ) )
{
return text;
}
if ( text.toLowerCase().startsWith( rootPath.toLowerCase() ) )
{
return text.substring( rootPath.length() + 1 );
}
File rootParent = root.getParentFile();
if ( rootParent == null )
{
return text;
}
String rootParentPath = rootParent.getCanonicalPath();
if ( rootParentPath.endsWith( File.separator ) )
{
rootParentPath = rootParentPath.substring( 0, rootParentPath.length() - 1 );
}
if ( rootParentPath.equals( "" ) )
{
return text;
}
if ( text.toLowerCase().startsWith( rootParentPath.toLowerCase() ) )
{
return ".." + File.separator + text.substring( rootParentPath.length() + 1 );
}
File rootParentParent = rootParent.getParentFile();
if ( rootParentParent == null )
{
return text;
}
String rootParentParentPath = rootParentParent.getCanonicalPath();
if ( rootParentParentPath.endsWith( File.separator ) )
{
rootParentParentPath = rootParentParentPath.substring( 0, rootParentParentPath.length() - 1 );
}
if ( rootParentParentPath.equals( "" ) )
{
return text;
}
if ( text.toLowerCase().startsWith( rootParentParentPath.toLowerCase() ) )
{
return ".." + File.separator + ".." + File.separator +
text.substring( rootParentParentPath.length() + 1 );
}
return text;
}
public void focusLost( final FocusEvent e )
{
GenericPanel.this.actionConfirmed();
}
public void focusGained( final FocusEvent e )
{
}
public void actionPerformed( final ActionEvent e )
{
if ( this.path != null )
{
try
{
File input = InputFieldUtilities.chooseInputFile( this.path, null );
if ( input == null )
{
return;
}
this.setText( input.getCanonicalPath() );
}
catch ( IOException e1 )
{
}
}
GenericPanel.this.actionConfirmed();
}
public JLabel getLabel()
{
return this.label;
}
}
public class ActionConfirmListener
extends ThreadedListener
{
@Override
protected void execute()
{
if ( getKeyCode() != KeyEvent.VK_ENTER )
{
return;
}
GenericPanel.this.actionConfirmed();
}
}
private class ConfirmedListener
extends ThreadedListener
{
@Override
protected void execute()
{
if ( GenericPanel.this.contentSet )
{
GenericPanel.this.actionConfirmed();
}
}
}
private class CancelledListener
extends ThreadedListener
{
@Override
protected void execute()
{
if ( GenericPanel.this.contentSet )
{
GenericPanel.this.actionCancelled();
}
}
}
}