/**
* 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.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.io.File;
import java.io.InputStream;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTabbedPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.util.Enumeration;
import java.util.Iterator;
import net.java.dev.spellcast.utilities.DataUtilities;
import net.java.dev.spellcast.utilities.JComponentUtilities;
import net.java.dev.spellcast.utilities.LockableListModel;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.KoLmafia;
import net.sourceforge.kolmafia.maximizer.Boost;
import net.sourceforge.kolmafia.maximizer.Maximizer;
import net.sourceforge.kolmafia.maximizer.MaximizerSpeculation;
import net.sourceforge.kolmafia.preferences.PreferenceListenerCheckBox;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.swingui.panel.GenericPanel;
import net.sourceforge.kolmafia.swingui.panel.ScrollablePanel;
import net.sourceforge.kolmafia.swingui.widget.AutoHighlightTextField;
import net.sourceforge.kolmafia.swingui.widget.GenericScrollPane;
import net.sourceforge.kolmafia.swingui.widget.ShowDescriptionList;
import net.sourceforge.kolmafia.utilities.ByteBufferUtilities;
import net.sourceforge.kolmafia.utilities.InputFieldUtilities;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class MaximizerFrame
extends GenericFrame
implements ListSelectionListener
{
public static final JComboBox expressionSelect = new JComboBox();
static
{ // This has to be done before the constructor runs, since the
// CLI "maximize" command can set the selected item prior to the
// frame being instantiated.
expressionSelect.setEditable( true );
KoLConstants.maximizerMList.updateJComboData( expressionSelect );
}
private SmartButtonGroup equipmentSelect, mallSelect;
private AutoHighlightTextField maxPriceField;
private JCheckBox includeAll;
private PreferenceListenerCheckBox foldableSelect, verboseSelect;
private final ShowDescriptionList boostList;
private JLabel listTitle = null;
private static String HELP_STRING;
static
{
InputStream stream = DataUtilities.getInputStream( KoLConstants.DATA_DIRECTORY, "maximizer-help.html", false );
byte[] bytes = ByteBufferUtilities.read( stream );
MaximizerFrame.HELP_STRING = StringUtilities.getEncodedString( bytes, "UTF-8" );
};
public MaximizerFrame()
{
super( "Modifier Maximizer" );
JPanel wrapperPanel = new JPanel( new BorderLayout() );
wrapperPanel.add( new MaximizerPanel(), BorderLayout.NORTH );
this.boostList = new ShowDescriptionList( Maximizer.boosts, 12 );
this.boostList.addListSelectionListener( this );
wrapperPanel.add( new BoostsPanel( this.boostList ), BorderLayout.CENTER );
this.setCenterComponent( wrapperPanel );
if ( Maximizer.eval != null )
{
this.valueChanged( null );
}
else
{
if ( Preferences.getInteger( "maximizerMRUSize" ) > 0 )
{
KoLConstants.maximizerMList.updateJComboData( expressionSelect );
}
}
}
@Override
public JTabbedPane getTabbedPane()
{
return null;
}
public void valueChanged( final ListSelectionEvent e )
{
double current = Maximizer.eval.getScore(
KoLCharacter.getCurrentModifiers() );
boolean failed = Maximizer.eval.failed;
Object[] items = this.boostList.getSelectedValues();
StringBuffer buff = new StringBuffer( "Current score: " );
buff.append( KoLConstants.FLOAT_FORMAT.format( current ) );
if ( failed )
{
buff.append( " (FAILED)" );
}
buff.append( " \u25CA Predicted: " );
if ( items.length == 0 )
{
buff.append( "---" );
}
else
{
MaximizerSpeculation spec = new MaximizerSpeculation();
for ( int i = 0; i < items.length; ++i )
{
if ( items[ i ] instanceof Boost )
{
((Boost) items[ i ]).addTo( spec );
}
}
double score = spec.getScore();
buff.append( KoLConstants.FLOAT_FORMAT.format( score ) );
buff.append( " (" );
buff.append( KoLConstants.MODIFIER_FORMAT.format( score - current ) );
if ( spec.failed )
{
buff.append( ", FAILED)" );
}
else
{
buff.append( ")" );
}
}
if ( this.listTitle != null )
{
this.listTitle.setText( buff.toString() );
}
if ( Preferences.getInteger( "maximizerMRUSize") > 0)
{
KoLConstants.maximizerMList.updateJComboData( expressionSelect );
}
}
public void maximize()
{
Maximizer.maximize( this.equipmentSelect.getSelectedIndex(),
InputFieldUtilities.getValue( this.maxPriceField ),
this.mallSelect.getSelectedIndex(),
this.includeAll.isSelected() );
this.valueChanged( null );
}
private class MaximizerPanel
extends GenericPanel
{
public MaximizerPanel()
{
super( "update", "help", new Dimension( 80, 20 ), new Dimension( 450, 20 ) );
MaximizerFrame.this.maxPriceField = new AutoHighlightTextField();
JComponentUtilities.setComponentSize( MaximizerFrame.this.maxPriceField, 80, -1 );
MaximizerFrame.this.foldableSelect = new PreferenceListenerCheckBox( "foldables", "maximizerFoldables" );
MaximizerFrame.this.includeAll = new JCheckBox( "effects with no direct source, skills you don't have, etc." );
MaximizerFrame.this.verboseSelect = new PreferenceListenerCheckBox( "show turns of effect and number of casts/items remaining", "verboseMaximizer" );
JPanel equipPanel = new JPanel( new FlowLayout( FlowLayout.LEADING, 0, 0 ) );
MaximizerFrame.this.equipmentSelect = new SmartButtonGroup( equipPanel );
MaximizerFrame.this.equipmentSelect.add( new JRadioButton( "none" ) );
MaximizerFrame.this.equipmentSelect.add( new JRadioButton( "on hand", true ) );
MaximizerFrame.this.equipmentSelect.add( new JRadioButton( "creatable" ) );
MaximizerFrame.this.equipmentSelect.add( new JRadioButton( "pullable/buyable" ) );
equipPanel.add( MaximizerFrame.this.foldableSelect );
JPanel mallPanel = new JPanel( new FlowLayout( FlowLayout.LEADING, 0, 0 ) );
mallPanel.add( MaximizerFrame.this.maxPriceField );
MaximizerFrame.this.mallSelect = new SmartButtonGroup( mallPanel );
MaximizerFrame.this.mallSelect.add( new JRadioButton( "don't check", true ) );
MaximizerFrame.this.mallSelect.add( new JRadioButton( "buyable only" ) );
MaximizerFrame.this.mallSelect.add( new JRadioButton( "all consumables" ) );
VerifiableElement[] elements = new VerifiableElement[ 5 ];
elements[ 0 ] = new VerifiableElement( "Maximize: ", MaximizerFrame.expressionSelect );
elements[ 1 ] = new VerifiableElement( "Equipment: ", equipPanel );
elements[ 2 ] = new VerifiableElement( "Max price: ", mallPanel );
elements[ 3 ] = new VerifiableElement( "Verbose: ", MaximizerFrame.this.verboseSelect );
elements[ 4 ] = new VerifiableElement( "Include: ", MaximizerFrame.this.includeAll );
this.setContent( elements );
}
@Override
public void actionConfirmed()
{
MaximizerFrame.this.maximize();
}
@Override
public void actionCancelled()
{
//InputFieldUtilities.alert( MaximizerFrame.HELP_STRING );
JLabel help = new JLabel( MaximizerFrame.HELP_STRING );
//JComponentUtilities.setComponentSize( help, 750, -1 );
GenericScrollPane content = new GenericScrollPane( help );
JComponentUtilities.setComponentSize( content, -1, 500 );
JOptionPane.showMessageDialog( this, content, "Modifier Maximizer help",
JOptionPane.PLAIN_MESSAGE );
}
}
private class BoostsPanel
extends ScrollablePanel
{
private final ShowDescriptionList elementList;
public BoostsPanel( final ShowDescriptionList list )
{
super( "Current score: --- \u25CA Predicted: ---",
"equip all", "exec selected", list );
this.elementList = (ShowDescriptionList) this.scrollComponent;
MaximizerFrame.this.listTitle = this.titleComponent;
}
@Override
public void actionConfirmed()
{
KoLmafia.forceContinue();
boolean any = false;
Iterator i = Maximizer.boosts.iterator();
while ( i.hasNext() )
{
Object boost = i.next();
if ( boost instanceof Boost )
{
boolean did = ((Boost) boost).execute( true );
if ( !KoLmafia.permitsContinue() ) return;
any |= did;
}
}
if ( any )
{
MaximizerFrame.this.maximize();
}
}
@Override
public void actionCancelled()
{
KoLmafia.forceContinue();
boolean any = false;
Object[] boosts = this.elementList.getSelectedValues();
for ( int i = 0; i < boosts.length; ++i )
{
if ( boosts[ i ] instanceof Boost )
{
boolean did = ((Boost) boosts[ i ]).execute( false );
if ( !KoLmafia.permitsContinue() ) return;
any |= did;
}
}
if ( any )
{
MaximizerFrame.this.maximize();
}
}
}
public static class SmartButtonGroup
extends ButtonGroup
{ // A version of ButtonGroup that actually does useful things:
// * Constructor takes a parent container, adding buttons to
// the group adds them to the container as well. This generally
// removes any need for a temp variable to hold the individual
// buttons as they're being created.
// * getSelectedIndex() to determine which button (0-based) is
// selected. How could that have been missing???
private Container parent;
public SmartButtonGroup( Container parent )
{
this.parent = parent;
}
@Override
public void add( AbstractButton b )
{
super.add( b );
parent.add( b );
}
public int getSelectedIndex()
{
int i = 0;
Enumeration e = this.getElements();
while ( e.hasMoreElements() )
{
if ( ((AbstractButton) e.nextElement()).isSelected() )
{
return i;
}
++i;
}
return -1;
}
}
}