/** * 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.widget; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.SystemColor; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.TransferHandler; import javax.swing.UIManager; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumn; import org.jdesktop.swingx.JXTable; import org.jdesktop.swingx.table.ColumnControlButton; import org.jdesktop.swingx.table.TableColumnExt; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import net.java.dev.spellcast.utilities.LockableListModel; import net.java.dev.spellcast.utilities.LockableListModel.ListElementFilter; import net.sourceforge.kolmafia.AdventureResult; import net.sourceforge.kolmafia.CreateFrameRunnable; import net.sourceforge.kolmafia.KoLConstants; import net.sourceforge.kolmafia.KoLmafiaCLI; import net.sourceforge.kolmafia.Modifiers; import net.sourceforge.kolmafia.MonsterData; import net.sourceforge.kolmafia.RequestThread; import net.sourceforge.kolmafia.StaticEntity; import net.sourceforge.kolmafia.maximizer.Boost; import net.sourceforge.kolmafia.moods.MoodManager; import net.sourceforge.kolmafia.moods.MoodTrigger; import net.sourceforge.kolmafia.objectpool.Concoction; import net.sourceforge.kolmafia.objectpool.ItemPool; import net.sourceforge.kolmafia.persistence.EffectDatabase; import net.sourceforge.kolmafia.persistence.InstalledScript; import net.sourceforge.kolmafia.persistence.ItemDatabase; import net.sourceforge.kolmafia.persistence.Script; import net.sourceforge.kolmafia.persistence.ScriptManager; import net.sourceforge.kolmafia.persistence.SkillDatabase; import net.sourceforge.kolmafia.preferences.Preferences; import net.sourceforge.kolmafia.request.AutoMallRequest; import net.sourceforge.kolmafia.request.AutoSellRequest; import net.sourceforge.kolmafia.request.CreateItemRequest; import net.sourceforge.kolmafia.request.PulverizeRequest; import net.sourceforge.kolmafia.request.PurchaseRequest; import net.sourceforge.kolmafia.request.UneffectRequest; import net.sourceforge.kolmafia.request.UseItemRequest; import net.sourceforge.kolmafia.request.UseSkillRequest; import net.sourceforge.kolmafia.session.StoreManager.SoldItem; import net.sourceforge.kolmafia.svn.SVNManager; import net.sourceforge.kolmafia.swingui.CommandDisplayFrame; import net.sourceforge.kolmafia.swingui.ProfileFrame; import net.sourceforge.kolmafia.swingui.listener.ThreadedListener; import net.sourceforge.kolmafia.swingui.menu.ThreadedMenuItem; import net.sourceforge.kolmafia.utilities.InputFieldUtilities; import net.sourceforge.kolmafia.utilities.StringUtilities; import net.sourceforge.kolmafia.utilities.WikiUtilities; import com.centerkey.BareBonesBrowserLaunch; import com.jgoodies.binding.adapter.AbstractTableAdapter; /* ShowDescriptionTable is a variant of ShowDescriptionList that extends a JXTable instead of a JList. It is meant so that you can simply instantiate ShowDescriptionTable instead of ShowDescriptionList, and all the "List-specific" methods will be provided in adapter methods. */ public class ShowDescriptionTable extends JXTable { public int lastSelectIndex; public JPopupMenu contextMenu; public ListElementFilter filter; private final LockableListModel displayModel, originalModel; private boolean[] flags; private AdaptedTableModel adaptedModel; private static final Pattern PLAYERID_MATCHER = Pattern.compile( "\\(#(\\d+)\\)" ); private final Comparator<String[]> arrayComparator = new Comparator<String[]>() { public int compare( String[] o1, String[] o2 ) { if ( o1.length != 2 || o2.length != 2 ) { return 0; } Integer i1 = Integer.valueOf( o1[1] ); Integer i2 = Integer.valueOf( o2[1] ); return i2.compareTo( i1 ); // descending order needed } }; public ShowDescriptionTable( final LockableListModel displayModel ) { this( displayModel, null, 4 ); } public ShowDescriptionTable( final LockableListModel displayModel, boolean[] flags ) { this( displayModel, null, 4, 3, flags ); } public ShowDescriptionTable( final LockableListModel displayModel, final int visibleRowCount ) { this( displayModel, null, visibleRowCount ); } public ShowDescriptionTable( final LockableListModel displayModel, final int visibleRowCount, final int visibleColumnCount ) { this( displayModel, null, visibleRowCount, visibleColumnCount, new boolean[] { false, false } ); } public ShowDescriptionTable( final LockableListModel displayModel, final ListElementFilter filter ) { this( displayModel, filter, 4 ); } public ShowDescriptionTable( final LockableListModel displayModel, final ListElementFilter filter, final int visibleRowCount ) { this( displayModel, filter, 4, 3, new boolean[] { false, false } ); } public ShowDescriptionTable( final LockableListModel displayModel, final ListElementFilter filter, final int visibleRowCount, final int visibleColumnCount, final boolean[] flags ) { this.contextMenu = new JPopupMenu(); this.flags = flags; boolean isMoodList = displayModel == MoodManager.getTriggers(); boolean isEncyclopedia = !displayModel.isEmpty() && displayModel.get( 0 ) instanceof Entry; boolean isMonster = isEncyclopedia && ((Entry)displayModel.get( 0 )).getValue() instanceof MonsterData; if ( !isMoodList ) { if ( displayModel.size() == 0 || !isEncyclopedia ) { this.contextMenu.add( new ContextMenuItem( "Game description", new DescriptionRunnable() ) ); } this.contextMenu.add( new ContextMenuItem( "Wiki description", new WikiLookupRunnable() ) ); } if ( displayModel == KoLConstants.activeEffects ) { this.contextMenu.add( new ContextMenuItem( "Remove this effect", new ShrugOffRunnable() ) ); this.contextMenu .add( new ContextMenuItem( "Add to current mood", new AddToMoodEffectRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Extend this effect", new ExtendEffectRunnable() ) ); } if ( displayModel == KoLConstants.usableSkills || displayModel == KoLConstants.availableSkills ) { this.contextMenu.add( new ContextMenuItem( "Cast the skill once", new CastSkillRunnable() ) ); this.contextMenu .add( new ContextMenuItem( "Add to current mood", new AddToMoodSkillRunnable() ) ); } if ( displayModel == KoLConstants.tally ) { this.contextMenu.add( new ContextMenuItem( "Zero out entries", new ZeroTallyRunnable() ) ); this.contextMenu.add( new JSeparator() ); this.contextMenu.add( new ContextMenuItem( "Add to junk list", new AddToJunkListRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Add to singleton list", new AddToSingletonListRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Add to memento list", new AddToMementoListRunnable() ) ); this.contextMenu.add( new JSeparator() ); this.contextMenu.add( new ContextMenuItem( "Autosell selected", new AutoSellRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Add selected to mall", new AutoMallRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Consume selected", new ConsumeRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Pulverize selected", new PulverizeRunnable() ) ); } else if ( displayModel == KoLConstants.inventory || displayModel == KoLConstants.closet || ( isEncyclopedia && !isMonster ) ) { this.contextMenu.add( new ContextMenuItem( "Add to junk list", new AddToJunkListRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Add to singleton list", new AddToSingletonListRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Add to memento list", new AddToMementoListRunnable() ) ); } else if ( isMoodList ) { this.contextMenu.add( new ContextMenuItem( "Force execution", new ForceExecuteRunnable() ) ); this.contextMenu.add( new ContextMenuItem( "Remove selected", new RemoveTriggerRunnable() ) ); this.addKeyListener( new RemoveTriggerListener() ); } this.addMouseListener( new PopupListener() ); // Add functionality for scrolling to an entry when the user types in a partial name. // This is provided natively by JList, but needs to be added here because tables do not natively provide // this behavior (for obvious reasons). this.addKeyListener( new KeyAdapter() { private long saved_ms = 0; private int TIMETOWAIT = 700; private String searchField = ""; @Override public void keyTyped( KeyEvent e ) { if ( e.isMetaDown() ) { // Workaround mac-specific issue: when meta (command) is pressed, keyTyped events still fire. // This is undesirable since meta-a is supposed to select all. Notably, command-a on windows // does not encounter this problem. return; } // the search "resets" after a brief pause. 700ms feels about right. if ( System.currentTimeMillis() - this.saved_ms < TIMETOWAIT ) { this.searchField = this.searchField + e.getKeyChar(); } else { this.searchField = "" + e.getKeyChar(); } ShowDescriptionTable.this.fireSearch( searchField ); this.saved_ms = System.currentTimeMillis(); } } ); this.originalModel = displayModel; this.displayModel = filter == null ? displayModel.getMirrorImage() : displayModel .getMirrorImage( filter ); String[] colNames = TableCellFactory.getColumnNames( this.originalModel, flags ); this.adaptedModel = new AdaptedTableModel( this.displayModel, colNames ); // this.getTableHeader().setReorderingAllowed( false ); this.setShowGrid( false ); this.setModel( this.adaptedModel ); // form of.. magic numbers this.getColumnModel().getColumn( 0 ).setPreferredWidth( 220 ); // Make the viewport behave this.setPreferredScrollableViewportSize( new Dimension( 1, 1 ) ); this.setVisibleRowCount( visibleRowCount ); // Enable column visibility control this.setColumnControlVisible( true ); ColumnControlButton btn = new ColumnControlButton( this ) { // Disable the "extra" visibility features which are added by default. // We have no need of installing horizontal scrollbars, packing columns, etc. @Override protected void addAdditionalActionItems() { } }; this.setColumnControl( btn ); // Set columns > visibleColumnCount to not visible. List<TableColumn> allColumns = getColumns( true ); for ( TableColumn t : allColumns ) { TableColumnExt ext = (TableColumnExt) t; ext.setComparator( new RenderedComparator( this.originalModel, ext.getModelIndex(), flags ) ); if ( ext.getModelIndex() >= visibleColumnCount ) { ext.setVisible( false ); } } this.setDefaultRenderer( String.class, new DescriptionTableRenderer( this.originalModel, flags ) ); this.setDefaultRenderer( Integer.class, new DescriptionTableRenderer( this.originalModel, flags ) ); this.setDefaultRenderer( JButton.class, new DescriptionTableRenderer( this.originalModel, flags ) ); this.setIntercellSpacing( new Dimension( 0, 0 ) ); // install a handler to provide saner clipboard behavior this.setTransferHandler( new ClipboardHandler() ); } protected void fireSearch( String searchField ) { if ( convertColumnIndexToModel( this.getSelectedColumn() ) != 0 ) { return; } for ( int i = 0; i < this.getRowCount(); i++ ) { String val = this.getValueAt( i, convertColumnIndexToModel( 0 ) ).toString().toLowerCase(); if ( val.startsWith( searchField.toLowerCase() ) ) { ShowDescriptionTable.this.setRowSelectionInterval( i, i ); ShowDescriptionTable.this.scrollCellToVisible( i, i ); break; } } } public void setColumnClasses( Class< ? >[] classDefs ) { String[] colNames = TableCellFactory.getColumnNames( this.originalModel, this.flags ); this.adaptedModel = new AdaptedTableModel( this.displayModel, colNames, classDefs ); this.setModel( this.adaptedModel ); } private class RenderedComparator implements Comparator<Object> { private int column; private boolean[] flags; private LockableListModel model; public RenderedComparator( LockableListModel originalModel, int column, boolean[] flags ) { this.model = originalModel; this.column = column; this.flags = flags; } public int compare( Object o1, Object o2 ) { Object o1val = TableCellFactory.get( this.column, this.model, o1, this.flags, false, true ); Object o2val = TableCellFactory.get( this.column, this.model, o2, this.flags, false, true ); if ( o1val instanceof Integer ) { if ( o2val == null ) { return 1; } Integer a1 = (Integer) o1val; Integer a2 = (Integer) o2val; return a1.compareTo( a2 ); } if ( o2val instanceof Integer ) { // o1val was null return -1; } if ( o1val instanceof String ) { if ( o2val == null ) { return 1; } String a1 = (String) o1val; String a2 = (String) o2val; return a1.compareToIgnoreCase( a2 ); } if ( o2val instanceof String ) { // o1val was null return -1; } return 0; } } public LockableListModel getOriginalModel() { return this.originalModel; } public LockableListModel getDisplayModel() { return displayModel; } // This is the adapted model object. ListModel -> Wrapper -> TableModel public class AdaptedTableModel extends AbstractTableAdapter { protected LockableListModel model; private Class<?>[] classDefs; public AdaptedTableModel( LockableListModel listModel, String[] columnNames ) { super( listModel, columnNames ); this.model = listModel; } public AdaptedTableModel( LockableListModel listModel, String[] columnNames, Class< ? >[] classDefs ) { super( listModel, columnNames ); this.model = listModel; this.classDefs = classDefs; } public Object getValueAt( int rowIndex, int columnIndex ) { return getRow( rowIndex ); } public Object getValueAt( int rowIndex ) { return getRow( rowIndex ); } public LockableListModel getModel() { return this.model; } @Override public Class<?> getColumnClass( int col ) { if ( this.classDefs != null ) { return classDefs[ col ]; } if ( col == 0 ) { // Item name should be the only column that we need to do a String compareTo(). It // should always be first. return String.class; } return Integer.class; } } public class DescriptionTableRenderer extends DefaultTableCellRenderer { protected LockableListModel model; private boolean[] flags; public DescriptionTableRenderer( LockableListModel originalModel, boolean[] flags ) { this.model = originalModel; this.flags = flags; } @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col ) { Object it = TableCellFactory.get( convertColumnIndexToModel( col ), this.model, value, this.flags, isSelected ); if ( it instanceof JButton ) { this.setToolTipText( ( (JButton) it ).getToolTipText() ); return (Component) it; } this.setValue( it ); this.setToolTipText( TableCellFactory.getTooltipText( value , flags ) ); if ( isSelected ) { this.setBackground( UIManager.getColor( "Table.selectionBackground" ) ); this.setForeground( UIManager.getColor( "Table.selectionForeground" ) ); } return this; } } private class PopupListener extends MouseAdapter { @Override public void mousePressed( final MouseEvent e ) { this.maybeShowPopup( e ); } @Override public void mouseReleased( final MouseEvent e ) { this.maybeShowPopup( e ); } private void maybeShowPopup( final MouseEvent e ) { if ( e.isPopupTrigger() ) { int index = ShowDescriptionTable.this.rowAtPoint( ( e.getPoint() ) ); if ( index == -1 ) { return; } ShowDescriptionTable.this.lastSelectIndex = index; if ( !ShowDescriptionTable.this.isRowSelected( ( index ) ) ) { ShowDescriptionTable.this.clearSelection(); ShowDescriptionTable.this.setRowSelectionInterval( index, index ); } ShowDescriptionTable.this.contextMenu.show( e.getComponent(), e.getX(), e.getY() ); } } } public class ClipboardHandler extends TransferHandler { @Override protected Transferable createTransferable( JComponent c ) { JTable t = (JTable) c; return new Selection( t ); } @Override public int getSourceActions( JComponent c ) { return COPY; } class Selection implements Transferable { private final JTable delegate; private final List<DataFlavor> flavors = new ArrayList<DataFlavor>(); public Selection( JTable t ) { this.flavors.add( DataFlavor.stringFlavor ); this.delegate = t; } public DataFlavor[] getTransferDataFlavors() { return flavors.toArray( new DataFlavor[ 0 ] ); } public boolean isDataFlavorSupported( DataFlavor flavor ) { return flavors.contains( flavor ); } public Object getTransferData( DataFlavor flavor ) throws UnsupportedFlavorException, IOException { int row = delegate.getSelectedRow(); return delegate.getValueAt( row, 0 ).toString(); } } } public static final void showGameDescription( Object item ) { if ( item instanceof Boost ) { item = ( (Boost) item ).getItem(); } if ( item instanceof AdventureResult ) { if ( ( (AdventureResult) item ).isItem() ) { StaticEntity.openDescriptionFrame( "desc_item.php?whichitem=" + ItemDatabase.getDescriptionId( ( (AdventureResult) item ).getItemId() ) ); } if ( ( (AdventureResult) item ).isStatusEffect() ) { StaticEntity.openDescriptionFrame( "desc_effect.php?whicheffect=" + EffectDatabase.getDescriptionId( EffectDatabase .getEffectId( ( (AdventureResult) item ).getName() ) ) ); } } else if ( item instanceof Concoction ) { StaticEntity.openDescriptionFrame( "desc_item.php?whichitem=" + ItemDatabase.getDescriptionId( ( (Concoction) item ).getItemId() ) ); } else if ( item instanceof CreateItemRequest ) { StaticEntity.openDescriptionFrame( "desc_item.php?whichitem=" + ItemDatabase.getDescriptionId( ( (CreateItemRequest) item ).getItemId() ) ); } else if ( item instanceof PurchaseRequest ) { StaticEntity.openDescriptionFrame( "desc_item.php?whichitem=" + ItemDatabase.getDescriptionId( ( (PurchaseRequest) item ).getItemId() ) ); } else if ( item instanceof UseSkillRequest ) { StaticEntity.openDescriptionFrame( "desc_skill.php?whichskill=" + ( (UseSkillRequest) item ).getSkillId() + "&self=true" ); } else if ( item instanceof SoldItem ) { StaticEntity.openDescriptionFrame( "desc_item.php?whichitem=" + ItemDatabase.getDescriptionId( ( (SoldItem) item ).getItemId() ) ); } else if ( item instanceof String ) { Matcher playerMatcher = ShowDescriptionTable.PLAYERID_MATCHER.matcher( (String) item ); if ( playerMatcher.find() ) { Object[] parameters = new Object[] { "#" + playerMatcher.group( 1 ) }; SwingUtilities.invokeLater( new CreateFrameRunnable( ProfileFrame.class, parameters ) ); } } } private class ContextMenuItem extends ThreadedMenuItem { public ContextMenuItem( final String title, final ThreadedListener action ) { super( title, action ); } } private abstract class ContextMenuListener extends ThreadedListener { public int index; public Object item; @Override protected void execute() { this.index = ShowDescriptionTable.this.lastSelectIndex == -1 ? ShowDescriptionTable.this .getSelectedRow() : ShowDescriptionTable.this.lastSelectIndex; this.item = ShowDescriptionTable.this.displayModel.getElementAt( ShowDescriptionTable.this .convertRowIndexToModel( this.index ) ); if ( this.item == null ) { return; } // ShowDescriptionTable.this.ensureIndexIsVisible( this.index ); this.executeAction(); } protected abstract void executeAction(); } /** * Utility class which shows the description of the item which is currently selected. */ private class DescriptionRunnable extends ContextMenuListener { @Override public void executeAction() { ShowDescriptionTable.showGameDescription( this.item ); } } /** * Utility class which shows the description of the item which is currently selected, as it appears on the wiki. */ private class WikiLookupRunnable extends ContextMenuListener { @Override public void executeAction() { WikiUtilities.showWikiDescription( this.item ); } } public void removeTriggers() { Object[] items = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); MoodManager.removeTriggers( items ); MoodManager.saveSettings(); } public Object[] getSelectedValues() { /* * Since this function exists for lists but not for tables, provide this as a pseudo-adapter function. * Note that we have to get the MODEL index from the sorter object, as there is possibly a * mapping of viewIndex -> modelIndex caused by sorting. */ int[] selectedRows = this.getSelectedRows(); Object[] selectedValues = new Object[ selectedRows.length ]; for ( int i = 0; i < selectedRows.length; ++i ) { selectedValues[ i ] = this.displayModel.getElementAt( this .convertRowIndexToModel( selectedRows[ i ] ) ); } return selectedValues; } public Object getSelectedValue() { /* * Since this function exists for lists but not for tables, provide this as a pseudo-adapter function. * Note that we have to get the MODEL index from the sorter object, as there is possibly a * mapping of viewIndex -> modelIndex caused by sorting. */ int selectedRow = this.getSelectedRow(); if ( selectedRow != -1 ) { return this.displayModel.getElementAt( this.convertRowIndexToModel( selectedRow ) ); } return null; } public AdventureResult[] getSelectedItems() { // Obviously, this only works if the model contains AdventureResults Object[] values = this.getSelectedValues(); AdventureResult[] result = new AdventureResult[ values.length ]; for ( int i = 0; i < values.length; ++i ) { result[ i ] = (AdventureResult)values[ i ]; } return result; } private class ForceExecuteRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] items = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); for ( int i = 0; i < items.length; ++i ) { KoLmafiaCLI.DEFAULT_SHELL.executeLine( ( (MoodTrigger) items[ i ] ).getAction() ); } } } private class RemoveTriggerRunnable extends ContextMenuListener { @Override public void executeAction() { ShowDescriptionTable.this.removeTriggers(); } } private class RemoveTriggerListener extends KeyAdapter { @Override public void keyReleased( final KeyEvent e ) { if ( e.isConsumed() ) { return; } if ( e.getKeyCode() != KeyEvent.VK_DELETE && e.getKeyCode() != KeyEvent.VK_BACK_SPACE ) { return; } ShowDescriptionTable.this.removeTriggers(); e.consume(); } } private class CastSkillRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] skills = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); UseSkillRequest request; for ( int i = 0; i < skills.length; ++i ) { request = (UseSkillRequest) skills[ i ]; request.setTarget( null ); request.setBuffCount( 1 ); RequestThread.postRequest( request ); } } } private class AddToMoodSkillRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] skills = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); if ( Preferences.getString( "currentMood" ).equals( "apathetic" ) ) { Preferences.setString( "currentMood", "default" ); } String name, action; for ( int i = 0; i < skills.length; ++i ) { name = UneffectRequest.skillToEffect( ( (UseSkillRequest) skills[ i ] ).getSkillName() ); action = MoodManager.getDefaultAction( "lose_effect", name ); if ( !action.equals( "" ) ) { MoodManager.addTrigger( "lose_effect", name, action ); } } MoodManager.saveSettings(); } } private class AddToMoodEffectRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] effects = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); if ( Preferences.getString( "currentMood" ).equals( "apathetic" ) ) { Preferences.setString( "currentMood", "default" ); } String name, action; for ( int i = 0; i < effects.length; ++i ) { name = ( (AdventureResult) effects[ i ] ).getName(); action = MoodManager.getDefaultAction( "lose_effect", name ); if ( !action.equals( "" ) ) { MoodManager.addTrigger( "lose_effect", name, action ); continue; } action = MoodManager.getDefaultAction( "gain_effect", name ); if ( !action.equals( "" ) ) { MoodManager.addTrigger( "gain_effect", name, action ); } } MoodManager.saveSettings(); } } private class ExtendEffectRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] effects = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); String name, action; for ( int i = 0; i < effects.length; ++i ) { name = ( (AdventureResult) effects[ i ] ).getName(); action = MoodManager.getDefaultAction( "lose_effect", name ); if ( !action.equals( "" ) ) { CommandDisplayFrame.executeCommand( action ); } } } } private class ShrugOffRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] effects = ShowDescriptionTable.this.getSelectedValues(); for ( int i = 0; i < effects.length; ++i ) { RequestThread.postRequest( new UneffectRequest( (AdventureResult) effects[ i ] ) ); } } } private class AddToJunkListRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] items = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); AdventureResult data; for ( int i = 0; i < items.length; ++i ) { data = null; if ( items[ i ] instanceof CreateItemRequest ) { data = ( (CreateItemRequest) items[ i ] ).createdItem; } else if ( items[ i ] instanceof AdventureResult && ( (AdventureResult) items[ i ] ).isItem() ) { data = (AdventureResult) items[ i ]; } else if ( items[ i ] instanceof String && ItemDatabase.contains( (String) items[ i ] ) ) { int itemId = ItemDatabase.getItemId( (String) items[ i ] ); data = ItemPool.get( itemId ); } else if ( items[ i ] instanceof Entry && ItemDatabase.contains( (String) ( (Entry) items[ i ] ).getValue() ) ) { int itemId = ItemDatabase.getItemId( (String) ( (Entry) items[ i ] ).getValue() ); data = ItemPool.get( itemId ); } if ( data == null ) { continue; } if ( !KoLConstants.junkList.contains( data ) ) { KoLConstants.junkList.add( data ); } } } } private class AddToSingletonListRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] items = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); AdventureResult data; for ( int i = 0; i < items.length; ++i ) { data = null; if ( items[ i ] instanceof CreateItemRequest ) { data = ( (CreateItemRequest) items[ i ] ).createdItem; } else if ( items[ i ] instanceof AdventureResult && ( (AdventureResult) items[ i ] ).isItem() ) { data = (AdventureResult) items[ i ]; } else if ( items[ i ] instanceof String && ItemDatabase.contains( (String) items[ i ] ) ) { int itemId = ItemDatabase.getItemId( (String) items[ i ] ); data = ItemPool.get( itemId ); } else if ( items[ i ] instanceof Entry && ItemDatabase.contains( (String) ( (Entry) items[ i ] ).getValue() ) ) { int itemId = ItemDatabase.getItemId( (String) ( (Entry) items[ i ] ).getValue() ); data = ItemPool.get( itemId ); } if ( data == null ) { continue; } if ( !KoLConstants.junkList.contains( data ) ) { KoLConstants.junkList.add( data ); } if ( !KoLConstants.singletonList.contains( data ) ) { KoLConstants.singletonList.add( data ); } } } } private class AddToMementoListRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] items = ShowDescriptionTable.this.getSelectedValues(); ShowDescriptionTable.this.clearSelection(); AdventureResult data; for ( int i = 0; i < items.length; ++i ) { data = null; if ( items[ i ] instanceof CreateItemRequest ) { data = ( (CreateItemRequest) items[ i ] ).createdItem; } else if ( items[ i ] instanceof AdventureResult && ( (AdventureResult) items[ i ] ).isItem() ) { data = (AdventureResult) items[ i ]; } else if ( items[ i ] instanceof String && ItemDatabase.contains( (String) items[ i ] ) ) { int itemId = ItemDatabase.getItemId( (String) items[ i ] ); data = ItemPool.get( itemId ); } else if ( items[ i ] instanceof Entry && ItemDatabase.contains( (String) ( (Entry) items[ i ] ).getValue() ) ) { int itemId = ItemDatabase.getItemId( (String) ( (Entry) items[ i ] ).getValue() ); data = ItemPool.get( itemId ); } if ( data != null && !KoLConstants.mementoList.contains( data ) ) { KoLConstants.mementoList.add( data ); } } Preferences.setBoolean( "mementoListActive", true ); } } private class ZeroTallyRunnable extends ContextMenuListener { @Override public void executeAction() { Object[] items = ShowDescriptionTable.this.getSelectedValues(); for ( int i = 0; i < items.length; ++i ) { AdventureResult item = (AdventureResult)items[ i ]; AdventureResult.addResultToList( KoLConstants.tally, item.getNegation() ); } } } private class AutoSellRunnable extends ContextMenuListener { @Override public void executeAction() { if ( !InputFieldUtilities.confirm( "Are you sure you would like to sell the selected items?" ) ) { return; } AdventureResult[] items = ShowDescriptionTable.this.getSelectedItems(); RequestThread.postRequest( new AutoSellRequest( items ) ); } } private class AutoMallRunnable extends ContextMenuListener { @Override public void executeAction() { if ( !InputFieldUtilities .confirm( "Are you sure you would like to add the selected items to your store?" ) ) { return; } AdventureResult[] items = ShowDescriptionTable.this.getSelectedItems(); RequestThread.postRequest( new AutoMallRequest( items ) ); } } private class ConsumeRunnable extends ContextMenuListener { @Override public void executeAction() { if ( !InputFieldUtilities.confirm( "Are you sure you want to use the selected items?" ) ) { return; } Object[] items = ShowDescriptionTable.this.getSelectedValues(); for ( int i = 0; i < items.length; ++i ) { RequestThread.postRequest( UseItemRequest.getInstance( (AdventureResult)items[ i ] ) ); } } } private class PulverizeRunnable extends ContextMenuListener { @Override public void executeAction() { if ( !InputFieldUtilities .confirm( "The items you've selected will be smashed to pieces. Are you sure?" ) ) { return; } Object[] items = ShowDescriptionTable.this.getSelectedValues(); for ( int i = 0; i < items.length; ++i ) { RequestThread.postRequest( new PulverizeRequest( (AdventureResult)items[ i ] ) ); } } } protected class InstallScriptRunnable extends ContextMenuListener { private ShowDescriptionTable table; public InstallScriptRunnable( ShowDescriptionTable table ) { this.table = table; } @Override protected void executeAction() { int row = this.table.getSelectedRow(); final Object ob = this.table.getValueAt( row, 0 ); if ( ob instanceof Script ) { RequestThread.postRequest( new Runnable() { public void run() { String installMe = ( (Script) ob ).getRepo(); try { SVNManager.doCheckout( SVNURL.parseURIEncoded( installMe ) ); } catch ( SVNException e ) { StaticEntity.printStackTrace( e ); return; } ScriptManager.updateRepoScripts( false ); ScriptManager.updateInstalledScripts(); } } ); } } } protected class DeleteScriptRunnable extends ContextMenuListener { private ShowDescriptionTable table; public DeleteScriptRunnable( ShowDescriptionTable table ) { this.table = table; } @Override protected void executeAction() { int row = this.table.getSelectedRow(); final Object ob = this.table.getValueAt( row, 0 ); if ( ob instanceof InstalledScript ) { RequestThread.postRequest( new Runnable() { public void run() { File deleteMe = ( (InstalledScript) ob ).getScriptFolder(); SVNManager.deleteInstalledProject( deleteMe ); if ( !deleteMe.exists() ) { ScriptManager.getInstalledScripts().remove( ob ); ScriptManager.updateRepoScripts( false ); } } } ); } } } protected class ShowThreadRunnable extends ContextMenuListener { private ShowDescriptionTable table; public ShowThreadRunnable( ShowDescriptionTable table ) { this.table = table; } @Override protected void executeAction() { int row = this.table.getSelectedRow(); final Object ob = this.table.getValueAt( row, 0 ); if ( ob instanceof Script ) { RequestThread.postRequest( new Runnable() { public void run() { String ft = ( (Script) ob ).getForumThread(); if ( ft != null && !ft.equals( "" ) ) BareBonesBrowserLaunch.openURL( Preferences.getString( "preferredWebBrowser" ), ft ); } } ); } } } protected class RefreshScriptsRunnable extends ContextMenuListener { public RefreshScriptsRunnable() { } @Override protected void executeAction() { RequestThread.postRequest( new Runnable() { public void run() { ScriptManager.updateInstalledScripts(); } } ); } } protected class UpdateScriptRunnable extends ContextMenuListener { private final ShowDescriptionTable table; private final boolean all; public UpdateScriptRunnable( ShowDescriptionTable table, boolean all ) { this.table = table; this.all = all; } @Override protected void executeAction() { if ( all ) { RequestThread.postRequest( new Runnable() { public void run() { SVNManager.doUpdate(); ScriptManager.updateInstalledScripts(); } } ); } else { RequestThread.postRequest( new Runnable() { public void run() { Object ob = UpdateScriptRunnable.this.table.getValueAt( table.getSelectedRow(), 0 ); if ( ob instanceof Script ) { try { SVNManager.doUpdate( SVNURL.parseURIEncoded( ( (Script) ob ).getRepo() ) ); } catch ( SVNException e ) { StaticEntity.printStackTrace( e ); return; } ScriptManager.updateInstalledScripts(); } } } ); } } } protected class ReloadRepoRunnable extends ContextMenuListener { public ReloadRepoRunnable() { } @Override protected void executeAction() { RequestThread.postRequest( new Runnable() { public void run() { ScriptManager.updateRepoScripts( true ); } } ); } } /* * And now a bunch of adapter functions. * These are methods that are provided in a list interface that are not provided in a table interface. */ public void ensureIndexIsVisible( int index ) { this.scrollRowToVisible( convertRowIndexToView( index ) ); } public int locationToIndex( Point point ) { return convertRowIndexToModel( this.rowAtPoint( point ) ); } public int getSelectedIndex() { return convertRowIndexToModel( this.getSelectedRow() ); } public void setSelectedIndex( int i ) { ShowDescriptionTable.this.setRowSelectionInterval( i, i ); } public void setCellRenderer( DefaultListCellRenderer renderer ) { // Blank method for now, no cellrenderer needed. // Eventually might want to do something with this? } public String collectHeaderStates() { // JViewPort, GenericScrollPane, JPanel, JPanel, JPanel, Inventory/Restore/etc... StringBuilder buffer = new StringBuilder(); List<TableColumn> cols = this.getColumns( true ); for ( int i = 0; i < cols.size(); ++i ) { if ( buffer.length() > 0 ) { buffer.append( "|" ); } buffer.append( cols.get( i ).getHeaderValue() ); buffer.append( ":" ); buffer.append( convertColumnIndexToView( cols.get( i ).getModelIndex() ) ); } buffer.append( ";" ); return buffer.toString(); } public void setHeaderStates( String rawPref ) { List<TableColumn> cols = this.getColumns( true ); ArrayList<String[]> sortCols = new ArrayList<String[]>(); // rawPref is a pipe-delimited list of (header name):(view index) String[] split1 = rawPref.split( "\\|" ); for ( String it : split1 ) { String[] split2 = it.split( "\\:" ); if ( split2.length != 2 ) { // malformed, or the first element (panel name) continue; } else { String[] entry = new String[] { split2[ 0 ], split2[ 1 ] }; sortCols.add( entry ); } } Collections.sort( sortCols, arrayComparator ); // Now, go through and set visibility. The comparator sorts things in descending order, so the first // column will be the highest index that's visible. for ( String[] it : sortCols ) { if ( it.length != 2 ) { // malformed, no idea how that happened. punt return; } for ( TableColumn t : cols ) { // find the column that matches the name if ( t.getHeaderValue().toString().equals( it[ 0 ] ) ) { // set it visible if its index isn't -1 this.getColumnExt( t.getHeaderValue() ).setVisible( Integer.valueOf( it[ 1 ] ) >= 0 ); break; } } } // All the columns have their visibility set now. Just move them into their proper order. for ( String[] it : sortCols ) { if ( it.length != 2 ) { // malformed, no idea how that happened. punt return; } if ( Integer.valueOf( it[ 1 ] ) < 0 ) { // Once we hit the negative ones, they're all negative after that. We're done. break; } for ( TableColumn t : cols ) { if ( t.getHeaderValue().toString().equals( it[ 0 ] ) ) { this.moveColumn( convertColumnIndexToView( t.getModelIndex() ), Integer.valueOf( it[ 1 ] ) ); break; } } } } }