/*
* EquipInfoTab.java
* Copyright 2010 Connor Petty <cpmeister@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Created on Jul 6, 2010, 5:08:49 PM
*/
package pcgen.gui2.tabs;
import static pcgen.gui2.tabs.equip.EquipmentSelection.equipmentArrayFlavor;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Insets;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.DropMode;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.RowSorter;
import javax.swing.SwingConstants;
import javax.swing.TransferHandler;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import pcgen.core.BodyStructure;
import pcgen.facade.core.BodyStructureFacade;
import pcgen.facade.core.CharacterFacade;
import pcgen.facade.core.EquipmentFacade;
import pcgen.facade.core.EquipmentSetFacade;
import pcgen.facade.core.EquipmentSetFacade.EquipNode;
import pcgen.facade.util.ReferenceFacade;
import pcgen.facade.util.event.ReferenceEvent;
import pcgen.facade.util.event.ReferenceListener;
import pcgen.gui2.UIPropertyContext;
import pcgen.gui2.filter.DisplayableFilter;
import pcgen.gui2.filter.SearchFilterPanel;
import pcgen.gui2.tabs.equip.EquipmentModel;
import pcgen.gui2.tabs.equip.EquipmentModels;
import pcgen.gui2.tabs.equip.EquipmentModels.EquipView;
import pcgen.gui2.tabs.equip.EquipmentSelection;
import pcgen.gui2.tabs.models.CharacterComboBoxModel;
import pcgen.gui2.tools.FlippingSplitPane;
import pcgen.gui2.tools.Icons;
import pcgen.gui2.tools.InfoPane;
import pcgen.gui2.tools.PrefTableColumnModel;
import pcgen.gui2.util.FontManipulation;
import pcgen.gui2.util.JDynamicTable;
import pcgen.gui2.util.JTreeTable;
import pcgen.gui2.util.event.PopupMouseAdapter;
import pcgen.gui2.util.table.DynamicTableColumnModel;
import pcgen.system.LanguageBundle;
import pcgen.util.enumeration.Load;
import pcgen.util.enumeration.Tab;
/**
* EquipInfoTab is a character tab for managing where gear is distributed for a
* character. Each set of distribution information is called an EquipSet.
* Multiple EquipSets can be managed to reflect different configurations.
*
* <br>
*
* @author Connor Petty <cpmeister@users.sourceforge.net>
*/
@SuppressWarnings("serial")
public class EquipInfoTab extends FlippingSplitPane implements CharacterInfoTab, TodoHandler
{
private static final DataFlavor equipNodeArrayFlavor = new DataFlavor(
DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" //$NON-NLS-1$
+ EquipNode[].class.getName() + "\"", null); //$NON-NLS-1$
private final JDynamicTable equipmentTable;
private final JComboBox equipViewBox;
private final JTreeTable equipmentSetTable;
private final InfoPane infoPane;
private final JButton unequipButton;
private final JButton unequipAllButton;
private final JButton moveUpButton;
private final JButton moveDownButton;
private final JButton equipButton;
private final JComboBox equipSetBox;
private final JButton newSetButton;
private final JButton removeSetButton;
private final JButton exportTemplateButton;
private final JButton viewBrowserButton;
private final JButton exportFileButton;
private final JButton setNoteButton;
private final JButton expandAllButton;
private final JButton collapseAllButton;
private final JLabel weightLabel;
private final JLabel loadLabel;
private final JLabel limitLabel;
private DisplayableFilter<Object, Object> tableFilter;
public EquipInfoTab()
{
super("Equip");
//TODO: remove this when optimized sorting is implemented
this.equipmentTable = new JDynamicTable()
{
@Override
public void setModel(TableModel dataModel)
{
RowSorter<? extends TableModel> oldRowSorter = getRowSorter();
super.setModel(dataModel);
RowSorter<? extends TableModel> newRowSorter = getRowSorter();
if (newRowSorter != null && oldRowSorter != null)
{
newRowSorter.setSortKeys(oldRowSorter.getSortKeys());
}
}
};
this.equipViewBox = new JComboBox(EquipView.values());
this.infoPane = new InfoPane();
this.equipmentSetTable = new JTreeTable()
{
@Override
protected void configureEnclosingScrollPane()
{
//We do nothing so the table is displayed without a header
}
};
this.equipButton = new JButton();
this.unequipButton = new JButton();
this.unequipAllButton = new JButton();
this.moveUpButton = new JButton();
this.moveDownButton = new JButton();
this.equipSetBox = new JComboBox();
this.newSetButton = new JButton();
this.removeSetButton = new JButton();
this.exportTemplateButton = new JButton();
this.viewBrowserButton = new JButton();
this.exportFileButton = new JButton();
this.setNoteButton = new JButton();
this.expandAllButton = new JButton();
this.collapseAllButton = new JButton();
this.weightLabel = new JLabel();
this.loadLabel = new JLabel();
this.limitLabel = new JLabel();
initComponents();
}
private void initComponents()
{
FontManipulation.small(newSetButton);
newSetButton.setMargin(new Insets(0, 0, 0, 0));
FontManipulation.small(removeSetButton);
removeSetButton.setMargin(new Insets(0, 0, 0, 0));
exportTemplateButton.setText(LanguageBundle.getString("in_equipExportTemplate")); //$NON-NLS-1$
viewBrowserButton.setText(LanguageBundle.getString("in_equipViewBrowser")); //$NON-NLS-1$
exportFileButton.setText(LanguageBundle.getString("in_equipExportFile")); //$NON-NLS-1$
setNoteButton.setText(LanguageBundle.getString("in_equipSetNote")); //$NON-NLS-1$
setOrientation(HORIZONTAL_SPLIT);
FlippingSplitPane splitPane = new FlippingSplitPane(VERTICAL_SPLIT, "EquipMain");
JPanel panel = new JPanel(new BorderLayout());
Box bar = Box.createHorizontalBox();
bar.add(Box.createHorizontalStrut(5));
bar.add(new JLabel(LanguageBundle.getString("in_equipView"))); //$NON-NLS-1$
bar.add(Box.createHorizontalStrut(5));
bar.add(equipViewBox);
bar.add(Box.createHorizontalStrut(5));
tableFilter = new SearchFilterPanel();
bar.add(tableFilter.getFilterComponent());
bar.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));
panel.add(bar, BorderLayout.NORTH);
equipmentTable.setAutoCreateColumnsFromModel(false);
equipmentTable.setColumnModel(createEquipmentColumnModel());
equipmentTable.setAutoCreateRowSorter(true);
panel.add(new JScrollPane(equipmentTable), BorderLayout.CENTER);
Box buttonsBox = Box.createHorizontalBox();
buttonsBox.add(Box.createHorizontalGlue());
equipButton.setHorizontalTextPosition(SwingConstants.LEADING);
buttonsBox.add(equipButton);
buttonsBox.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
panel.add(buttonsBox, BorderLayout.SOUTH);
splitPane.setTopComponent(panel);
splitPane.setBottomComponent(infoPane);
setLeftComponent(splitPane);
panel = new JPanel(new BorderLayout());
Box equipPane = Box.createVerticalBox();
Box box = Box.createHorizontalBox();
box.add(Box.createHorizontalGlue());
box.add(new JLabel(LanguageBundle.getString("in_equipSetLabel"))); //$NON-NLS-1$
box.add(Box.createHorizontalStrut(3));
box.add(equipSetBox);
box.add(Box.createHorizontalStrut(3));
box.add(newSetButton);
box.add(Box.createHorizontalStrut(3));
box.add(removeSetButton);
box.add(Box.createHorizontalGlue());
box.add(new JLabel(LanguageBundle.getString("in_equipWeightLabel"))); //$NON-NLS-1$
box.add(Box.createHorizontalStrut(5));
box.add(weightLabel);
box.add(Box.createHorizontalGlue());
box.add(new JLabel(LanguageBundle.getString("in_equipLoadLabel"))); //$NON-NLS-1$
box.add(Box.createHorizontalStrut(5));
box.add(loadLabel);
// box.add(Box.createHorizontalGlue());
// box.add(new JLabel("Limit:"));
box.add(Box.createHorizontalStrut(5));
box.add(limitLabel);
box.add(Box.createHorizontalGlue());
equipPane.add(Box.createVerticalStrut(3));
equipPane.add(box);
equipPane.add(Box.createVerticalStrut(3));
box = Box.createHorizontalBox();
box.add(exportTemplateButton);
exportTemplateButton.setEnabled(false);
box.add(Box.createHorizontalStrut(3));
box.add(viewBrowserButton);
viewBrowserButton.setEnabled(false);
box.add(Box.createHorizontalStrut(3));
box.add(exportFileButton);
exportFileButton.setEnabled(false);
box.add(Box.createHorizontalStrut(3));
box.add(setNoteButton);
setNoteButton.setEnabled(false);
box.add(Box.createHorizontalStrut(3));
box.add(expandAllButton);
box.add(Box.createHorizontalStrut(3));
box.add(collapseAllButton);
equipPane.add(box);
equipPane.add(Box.createVerticalStrut(3));
panel.add(equipPane, BorderLayout.NORTH);
EquipmentModel.initializeTreeTable(equipmentSetTable);
panel.add(new JScrollPane(equipmentSetTable), BorderLayout.CENTER);
Box selPanelbuttonsBox = Box.createHorizontalBox();
selPanelbuttonsBox.add(Box.createHorizontalStrut(3));
selPanelbuttonsBox.add(unequipButton);
selPanelbuttonsBox.add(Box.createHorizontalStrut(3));
selPanelbuttonsBox.add(unequipAllButton);
selPanelbuttonsBox.add(Box.createHorizontalStrut(3));
selPanelbuttonsBox.add(moveUpButton);
selPanelbuttonsBox.add(Box.createHorizontalStrut(3));
selPanelbuttonsBox.add(moveDownButton);
selPanelbuttonsBox.add(Box.createHorizontalGlue());
selPanelbuttonsBox.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
panel.add(selPanelbuttonsBox, BorderLayout.SOUTH);
setRightComponent(panel);
}
private DynamicTableColumnModel createEquipmentColumnModel()
{
PrefTableColumnModel model = new PrefTableColumnModel("EquipList", 1);
TableColumn column = new TableColumn(0);
column.setHeaderValue(LanguageBundle.getString("in_nameLabel")); //$NON-NLS-1$
model.addColumn(column, true, 150);
column = new TableColumn(1);
column.setHeaderValue(LanguageBundle.getString("in_type")); //$NON-NLS-1$
model.addColumn(column, true, 75);
column = new TableColumn(2);
column.setHeaderValue(LanguageBundle.getString("in_equipLocationAbbrev")); //$NON-NLS-1$
model.addColumn(column, true, 75);
column = new TableColumn(3);
column.setHeaderValue(LanguageBundle.getString("in_equipQuantityAbbrev")); //$NON-NLS-1$
model.addColumn(column, true, 75);
column = new TableColumn(4);
column.setHeaderValue(LanguageBundle.getString("in_equipWeightAbbrev")); //$NON-NLS-1$
model.addColumn(column, true, 75);
column = new TableColumn(5);
column.setHeaderValue(LanguageBundle.getString("in_descrip")); //$NON-NLS-1$
model.addColumn(column, false, 75);
return model;
}
@Override
public ModelMap createModels(CharacterFacade character)
{
ModelMap models = new ModelMap();
models.put(EquipmentModel.class, new EquipmentModel(character, equipmentSetTable));
models.put(EquipmentModels.class, new EquipmentModels(character,
equipViewBox, equipmentTable, tableFilter, equipmentSetTable,
equipButton, unequipButton, moveUpButton, moveDownButton));
models.put(UnequipAllAction.class, new UnequipAllAction(character));
models.put(EquipSetBoxModel.class, new EquipSetBoxModel(character));
models.put(AddSetAction.class, new AddSetAction(character));
models.put(RemoveSetAction.class, new RemoveSetAction(character));
models.put(LabelsUpdater.class, new LabelsUpdater(character));
models.put(EquipInfoHandler.class, new EquipInfoHandler(character));
models.put(EquipmentRenderer.class, new EquipmentRenderer(character));
models.put(EquipmentTransferHandler.class, new EquipmentTransferHandler(character));
models.put(EquipmentSetTransferHandler.class, new EquipmentSetTransferHandler(character));
models.put(OrderPopupMenuHandler.class, new OrderPopupMenuHandler(character));
models.put(ExpandAllAction.class, new ExpandAllAction());
models.put(CollapseAllAction.class, new CollapseAllAction());
return models;
}
@Override
public void restoreModels(ModelMap models)
{
models.get(EquipmentModel.class).install();
models.get(EquipmentModels.class).install();
models.get(LabelsUpdater.class).install();
models.get(EquipInfoHandler.class).install();
models.get(EquipmentRenderer.class).install();
models.get(EquipmentTransferHandler.class).install();
models.get(EquipmentSetTransferHandler.class).install();
models.get(OrderPopupMenuHandler.class).install();
unequipAllButton.setAction(models.get(UnequipAllAction.class));
newSetButton.setAction(models.get(AddSetAction.class));
removeSetButton.setAction(models.get(RemoveSetAction.class));
expandAllButton.setAction(models.get(ExpandAllAction.class));
collapseAllButton.setAction(models.get(CollapseAllAction.class));
equipSetBox.setModel(models.get(EquipSetBoxModel.class));
}
@Override
public void storeModels(ModelMap models)
{
models.get(LabelsUpdater.class).uninstall();
models.get(EquipmentModel.class).uninstall();
models.get(EquipmentModels.class).uninstall();
models.get(EquipInfoHandler.class).uninstall();
models.get(OrderPopupMenuHandler.class).uninstall();
}
@Override
public TabTitle getTabTitle()
{
return new TabTitle(Tab.EQUIPPING);
}
private List<Integer> getMenuTargets(JTable table, MouseEvent e)
{
int row = table.rowAtPoint(e.getPoint());
if (!table.isRowSelected(row))
{
table.setRowSelectionInterval(row, row);
}
List<Integer> targets = new ArrayList<>();
for (int selRow : table.getSelectedRows())
{
targets.add(selRow);
}
return targets;
}
/**
*/
public void setLoadLabel(String text)
{
// bold / highlight text based on encumbrance value
Font font = loadLabel.getFont();
Color color = UIPropertyContext.getQualifiedColor();
Load encumbrance = Load.getLoadType(text);
switch (encumbrance)
{
case MEDIUM:
font = FontManipulation.bold(font);
color = UIPropertyContext.getAutomaticColor();
break;
case HEAVY:
font = FontManipulation.bold_italic(font);
color = UIPropertyContext.getVirtualColor();
break;
case OVERLOAD:
font = FontManipulation.bold_italic(font);
color = UIPropertyContext.getNotQualifiedColor();
break;
default:
font = FontManipulation.plain(font);
}
loadLabel.setText(text);
loadLabel.setFont(font);
loadLabel.setForeground(color);
}
@Override
public void adviseTodo(String fieldName)
{
// We don't provide further advice at this time.
}
private class AddSetAction extends AbstractAction
{
private final CharacterFacade character;
public AddSetAction(CharacterFacade character)
{
super(LanguageBundle.getString("in_new")); //$NON-NLS-1$
this.character = character;
}
@Override
public void actionPerformed(ActionEvent e)
{
String name = JOptionPane.showInputDialog(JOptionPane.getFrameForComponent(EquipInfoTab.this), "Name of new set");
if (StringUtils.isNotEmpty(name))
{
character.setEquipmentSet(character.createEquipmentSet(name));
}
}
}
private class RemoveSetAction extends AbstractAction
{
private final CharacterFacade character;
public RemoveSetAction(CharacterFacade character)
{
super(LanguageBundle.getString("in_remove")); //$NON-NLS-1$
this.character = character;
}
@Override
public void actionPerformed(ActionEvent e)
{
character.deleteEquipmentSet(character.getEquipmentSetRef().get());
}
}
private class EquipSetBoxModel extends CharacterComboBoxModel<EquipmentSetFacade>
{
private final CharacterFacade character;
public EquipSetBoxModel(CharacterFacade character)
{
this.character = character;
setListFacade(character.getEquipmentSets());
setReference(character.getEquipmentSetRef());
}
@Override
public void setSelectedItem(Object anItem)
{
character.setEquipmentSet((EquipmentSetFacade) anItem);
}
}
private class ExpandAllAction extends AbstractAction
{
public ExpandAllAction()
{
super("+"); //$NON-NLS-1$
putValue(SHORT_DESCRIPTION, LanguageBundle.getString("in_expandAllTip")); //$NON-NLS-1$
}
@Override
public void actionPerformed(ActionEvent e)
{
JTree tree = equipmentSetTable.getTree();
for (int i = 0; i < tree.getRowCount(); i++)
{
tree.expandRow(i);
}
}
}
private class CollapseAllAction extends AbstractAction
{
public CollapseAllAction()
{
super("-"); //$NON-NLS-1$
putValue(SHORT_DESCRIPTION, LanguageBundle.getString("in_collapseAllTip")); //$NON-NLS-1$
}
@Override
public void actionPerformed(ActionEvent e)
{
JTree tree = equipmentSetTable.getTree();
for (int i = tree.getRowCount() - 1; i >= 0; i--)
{
tree.collapseRow(i);
}
}
}
private class UnequipAllAction extends AbstractAction
{
private final CharacterFacade character;
public UnequipAllAction(CharacterFacade character)
{
super(LanguageBundle.getString("in_equipUnequipAll")); //$NON-NLS-1$
this.character = character;
}
@Override
public void actionPerformed(ActionEvent e)
{
int ret
= JOptionPane.showConfirmDialog(EquipInfoTab.this,
LanguageBundle.getString("in_equipUnequipConfirm"), //$NON-NLS-1$
LanguageBundle.getString("in_areYouSure"), //$NON-NLS-1$
JOptionPane.YES_NO_OPTION);
if (ret == JOptionPane.YES_OPTION)
{
character.getEquipmentSetRef().get().removeAllEquipment();
}
}
}
private class LabelsUpdater implements ReferenceListener<String>
{
private final ReferenceFacade<String> weightRef;
private final ReferenceFacade<String> loadRef;
private final ReferenceFacade<String> limitRef;
public LabelsUpdater(CharacterFacade character)
{
weightRef = character.getCarriedWeightRef();
loadRef = character.getLoadRef();
limitRef = character.getWeightLimitRef();
}
public void install()
{
weightLabel.setText(weightRef.get());
setLoadLabel(loadRef.get());
limitLabel.setText(limitRef.get());
weightRef.addReferenceListener(this);
loadRef.addReferenceListener(this);
limitRef.addReferenceListener(this);
}
public void uninstall()
{
weightRef.removeReferenceListener(this);
loadRef.removeReferenceListener(this);
limitRef.removeReferenceListener(this);
}
@Override
public void referenceChanged(ReferenceEvent<String> e)
{
Object source = e.getSource();
if (source == weightRef)
{
weightLabel.setText(e.getNewReference());
}
else if (source == loadRef)
{
setLoadLabel(e.getNewReference());
}
else
{
limitLabel.setText(e.getNewReference());
}
}
}
private class EquipInfoHandler implements ListSelectionListener
{
private CharacterFacade character;
private String text;
public EquipInfoHandler(CharacterFacade character)
{
this.character = character;
this.text = ""; //$NON-NLS-1$
}
public void install()
{
equipmentTable.getSelectionModel().addListSelectionListener(this);
equipmentSetTable.getSelectionModel().addListSelectionListener(this);
infoPane.setText(text);
}
public void uninstall()
{
equipmentTable.getSelectionModel().removeListSelectionListener(this);
equipmentSetTable.getSelectionModel().removeListSelectionListener(this);
}
@Override
public void valueChanged(ListSelectionEvent e)
{
JTable target = equipmentTable;
if (equipmentSetTable.getSelectionModel().equals(e.getSource()))
{
target = equipmentSetTable;
}
if (!e.getValueIsAdjusting())
{
int selectedRows[] = target.getSelectedRows();
StringBuilder sb = new StringBuilder(2000);
for (int row : selectedRows)
{
EquipmentFacade equip = null;
if (row != -1)
{
Object value = target.getModel().getValueAt(row, 0);
if (value instanceof EquipmentFacade)
{
equip = (EquipmentFacade) value;
}
else if (value instanceof EquipNode)
{
equip = ((EquipNode) value).getEquipment();
}
}
if (equip != null)
{
sb.append(character.getInfoFactory().getHTMLInfo(equip));
}
}
text = "<html>" + sb.toString() + "</html>"; //$NON-NLS-1$ //$NON-NLS-2$
infoPane.setText(text);
}
}
}
private class EquipmentRenderer extends DefaultTableCellRenderer
{
private CharacterFacade character;
public EquipmentRenderer(CharacterFacade character)
{
this.character = character;
}
public void install()
{
equipmentTable.setDefaultRenderer(Object.class, this);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (value instanceof EquipmentFacade
&& !character.isQualifiedFor((EquipmentFacade) value))
{
setForeground(UIPropertyContext.getNotQualifiedColor());
}
else if (!isSelected)
{
setForeground(UIPropertyContext.getQualifiedColor());
}
return this;
}
}
private static class EquipNodeSelection implements Transferable
{
private static DataFlavor[] FLAVORS = new DataFlavor[]
{
equipNodeArrayFlavor,
equipmentArrayFlavor
};
private EquipNode[] nodeArray;
public EquipNodeSelection(EquipNode[] nodeArray)
{
this.nodeArray = nodeArray;
}
@Override
public DataFlavor[] getTransferDataFlavors()
{
return FLAVORS;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor)
{
return flavor == FLAVORS[0] || flavor == FLAVORS[1];
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException
{
if (flavor == equipNodeArrayFlavor)
{
return nodeArray;
}
if (flavor == equipmentArrayFlavor)
{
EquipmentFacade[] equipArray = new EquipmentFacade[nodeArray.length];
for (int i = 0; i < equipArray.length; i++)
{
equipArray[i] = nodeArray[i].getEquipment();
}
return equipArray;
}
throw new UnsupportedFlavorException(flavor);
}
}
private class EquipmentTransferHandler extends TransferHandler
{
private CharacterFacade character;
public EquipmentTransferHandler(CharacterFacade character)
{
this.character = character;
}
public void install()
{
equipmentTable.setDragEnabled(true);
equipmentTable.setDropMode(DropMode.ON);
equipmentTable.setTransferHandler(this);
}
@Override
public int getSourceActions(JComponent c)
{
return MOVE;
}
@Override
protected Transferable createTransferable(JComponent c)
{
if (c == equipmentTable)
{
int[] rows = equipmentTable.getSelectedRows();
if (ArrayUtils.isEmpty(rows))
{
return null;
}
EquipmentFacade[] equipArray = new EquipmentFacade[rows.length];
for (int i = 0; i < equipArray.length; i++)
{
equipArray[i] = (EquipmentFacade) equipmentTable.getModel().getValueAt(rows[i], 0);
}
return new EquipmentSelection(equipArray);
}
return super.createTransferable(c);
}
@Override
public boolean canImport(TransferSupport support)
{
if (!support.isDataFlavorSupported(equipNodeArrayFlavor))
{
return false;
}
support.setShowDropLocation(false);
return true;
}
private EquipNode[] getEquipNodeArray(TransferSupport support)
{
EquipNode[] equipNodeArray = null;
try
{
equipNodeArray = (EquipNode[]) support.getTransferable().getTransferData(equipNodeArrayFlavor);
}
catch (UnsupportedFlavorException | IOException ex)
{
Logger.getLogger(EquipInfoTab.class.getName()).log(Level.SEVERE, null, ex);
}
return equipNodeArray;
}
@Override
public boolean importData(TransferSupport support)
{
if (!canImport(support))
{
return false;
}
if (!support.isDrop())
{
return false;
}
EquipNode[] nodes = getEquipNodeArray(support);
if (nodes == null)
{
return false;
}
EquipmentSetFacade equipSet = character.getEquipmentSetRef().get();
for (EquipNode equipNode : nodes)
{
equipSet.removeEquipment(equipNode, 1);
}
return true;
}
}
private class EquipmentSetTransferHandler extends TransferHandler
{
private CharacterFacade character;
public EquipmentSetTransferHandler(CharacterFacade character)
{
this.character = character;
}
public void install()
{
equipmentSetTable.setTransferHandler(this);
equipmentSetTable.setDragEnabled(true);
equipmentSetTable.setDropMode(DropMode.ON_OR_INSERT_ROWS);
}
@Override
public int getSourceActions(JComponent c)
{
return MOVE;
}
@Override
protected Transferable createTransferable(JComponent c)
{
if (c == equipmentSetTable)
{
int[] rows = equipmentSetTable.getSelectedRows();
if (ArrayUtils.isEmpty(rows))
{
return null;
}
EquipNode[] nodeArray = new EquipNode[rows.length];
for (int i = 0; i < nodeArray.length; i++)
{
nodeArray[i] = (EquipNode) equipmentSetTable.getModel().getValueAt(rows[i], 0);
}
return new EquipNodeSelection(nodeArray);
}
return super.createTransferable(c);
}
private EquipmentFacade[] getEquipmentArray(TransferSupport support)
{
EquipmentFacade[] equipmentArray = null;
try
{
equipmentArray = (EquipmentFacade[]) support.getTransferable().getTransferData(equipmentArrayFlavor);
}
catch (UnsupportedFlavorException | IOException ex)
{
Logger.getLogger(EquipInfoTab.class.getName()).log(Level.SEVERE, null, ex);
}
return equipmentArray;
}
private EquipNode[] getEquipNodeArray(TransferSupport support)
{
EquipNode[] equipNodeArray = null;
try
{
equipNodeArray = (EquipNode[]) support.getTransferable().getTransferData(equipNodeArrayFlavor);
}
catch (UnsupportedFlavorException | IOException ex)
{
Logger.getLogger(EquipInfoTab.class.getName()).log(Level.SEVERE, null, ex);
}
return equipNodeArray;
}
@Override
public boolean canImport(TransferSupport support)
{
JTable.DropLocation location = (JTable.DropLocation) support.getDropLocation();
int row = location.getRow();
EquipNode node = (EquipNode) equipmentSetTable.getValueAt(row, 0);
if (node == null)
{
return false;
}
if (location.isInsertRow())
{
node = node.getParent();
}
EquipmentSetFacade equipSet = character.getEquipmentSetRef().get();
if (support.isDataFlavorSupported(equipNodeArrayFlavor))
{
EquipNode[] equipNodeArray = getEquipNodeArray(support);
if (equipNodeArray == null)
{
return false;
}
for (EquipNode equipNode : equipNodeArray)
{
if (!equipSet.canEquip(node, equipNode.getEquipment()))
{
return false;
}
}
return true;
}
else if (support.isDataFlavorSupported(equipmentArrayFlavor))
{
EquipmentFacade[] equipmentArray = getEquipmentArray(support);
if (equipmentArray == null)
{
return false;
}
for (EquipmentFacade equipmentFacade : equipmentArray)
{
if (!equipSet.canEquip(node, equipmentFacade))
{
return false;
}
}
return true;
}
return false;
}
@Override
public boolean importData(TransferSupport support)
{
if (!canImport(support) || !support.isDrop())
{
return false;
}
JTable.DropLocation location = (JTable.DropLocation) support.getDropLocation();
int row = location.getRow();
EquipNode node = (EquipNode) equipmentSetTable.getValueAt(row, 0);
EquipNode beforeNode = null;
if (location.isInsertRow())
{
beforeNode = node;
node = node.getParent();
}
EquipmentSetFacade equipSet = character.getEquipmentSetRef().get();
if (support.isDataFlavorSupported(equipNodeArrayFlavor))
{
EquipNode[] equipNodeArray = getEquipNodeArray(support);
if (equipNodeArray == null)
{
return false;
}
for (EquipNode equipNode : equipNodeArray)
{
int quantity = equipSet.getQuantity(equipNode);
equipSet.removeEquipment(equipNode, quantity);
equipSet.addEquipment(node, equipNode.getEquipment(), quantity, beforeNode);
}
}
else if (support.isDataFlavorSupported(equipmentArrayFlavor))
{
EquipmentFacade[] equipmentArray = getEquipmentArray(support);
if (equipmentArray == null)
{
return false;
}
for (EquipmentFacade equipmentFacade : equipmentArray)
{
equipSet.addEquipment(node, equipmentFacade, 1, beforeNode);
}
}
return true;
}
}
private class OrderPopupMenuHandler extends PopupMouseAdapter
{
private final CharacterFacade character;
OrderPopupMenuHandler(CharacterFacade character)
{
this.character = character;
}
@Override
public void showPopup(MouseEvent e)
{
List<Integer> targets = getMenuTargets(equipmentSetTable, e);
if (targets.isEmpty())
{
return;
}
List<EquipNode> upTargets = new ArrayList<>();
List<EquipNode> downTargets = new ArrayList<>();
List<EquipNode> sortTargets = new ArrayList<>();
EquipNode[] relativeNodes = filterTargets(targets, upTargets, downTargets, sortTargets);
JPopupMenu popupMenu = new JPopupMenu();
if (!upTargets.isEmpty() || !downTargets.isEmpty())
{
popupMenu.add(new MoveEquipUpMenuItem(character, upTargets, relativeNodes[0]));
popupMenu.add(new MoveEquipDownMenuItem(character, downTargets, relativeNodes[1]));
}
if (!sortTargets.isEmpty())
{
if (!upTargets.isEmpty() || !downTargets.isEmpty())
{
popupMenu.addSeparator();
}
popupMenu.add(new SortEquipMenuItem(character, sortTargets));
}
if (popupMenu.getComponents().length > 0)
{
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
private EquipNode[] filterTargets(List<Integer> targetRows,
List<EquipNode> upTargets, List<EquipNode> downTargets,
List<EquipNode> sortTargets)
{
EquipmentSetFacade equipSet = character.getEquipmentSetRef().get();
TableModel equipSetModel = equipmentSetTable.getModel();
int beforeRow = equipSetModel.getRowCount();
int afterRow = 0;
for (Integer selRow : targetRows)
{
Object value = equipSetModel.getValueAt(selRow, 0);
if (!(value instanceof EquipNode))
{
continue;
}
EquipNode equipNode = (EquipNode) value;
if (!isInGeneralBodyStructure(equipNode))
{
continue;
}
switch (equipNode.getNodeType())
{
case BODY_SLOT:
sortTargets.add(equipNode);
break;
case EQUIPMENT:
// Check node is not the top item in the parent
upTargets.add(equipNode);
downTargets.add(equipNode);
// Check item is a container
if (equipSet.isContainer(equipNode.getEquipment()))
{
sortTargets.add(equipNode);
}
break;
default:
break;
}
}
// Set the before and after nodes
EquipNode[] relativeNodes = new EquipNode[]
{
null, null
};
if (beforeRow >= 0)
{
relativeNodes[0]
= (EquipNode) equipSetModel.getValueAt(beforeRow, 0);
}
if (afterRow < equipSetModel.getRowCount())
{
relativeNodes[1]
= (EquipNode) equipSetModel.getValueAt(afterRow, 0);
}
return relativeNodes;
}
/**
* Identify if the EquipNode is within one of the general body
* structures (equipped, carried and not carried)
*
* @param equipNode The node to check.
* @return true if it is in a general body structure.
*/
private boolean isInGeneralBodyStructure(EquipNode equipNode)
{
BodyStructureFacade bodyStructure
= equipNode.getBodyStructure();
return (bodyStructure instanceof BodyStructure
&& ((BodyStructure) bodyStructure).getEquipSlots()
.isEmpty());
}
public void install()
{
equipmentSetTable.addMouseListener(this);
}
public void uninstall()
{
equipmentSetTable.removeMouseListener(this);
}
}
/**
* Menu item for moving the selected equipment up a step in their container.
*/
private class MoveEquipUpMenuItem extends JMenuItem implements ActionListener
{
private final CharacterFacade character;
private final List<EquipNode> targets;
private final EquipNode beforeNode;
MoveEquipUpMenuItem(CharacterFacade character, List<EquipNode> targets, EquipNode beforeNode)
{
super(LanguageBundle.getString("in_equipMoveUpMenuCommand")); //$NON-NLS-1$
this.character = character;
this.targets = targets;
this.beforeNode = beforeNode;
setToolTipText(LanguageBundle.getString("in_equipMoveUpMenuDesc")); //$NON-NLS-1$
setIcon(Icons.Up16.getImageIcon());
setEnabled(!targets.isEmpty());
addActionListener(this);
}
/**
* Action to move the current item up in the current container
*/
@Override
public void actionPerformed(ActionEvent e)
{
EquipmentSetFacade equipSet
= character.getEquipmentSetRef().get();
for (EquipNode equipNode : targets)
{
equipSet.moveEquipment(equipNode, -1);
}
}
}
/**
* Menu item for moving the selected equipment up a step in their container.
*/
private class MoveEquipDownMenuItem extends JMenuItem implements ActionListener
{
private final CharacterFacade character;
private final List<EquipNode> targets;
private final EquipNode afterNode;
MoveEquipDownMenuItem(CharacterFacade character, List<EquipNode> targets, EquipNode beforeNode)
{
super(LanguageBundle.getString("in_equipMoveDownMenuCommand")); //$NON-NLS-1$
this.character = character;
this.targets = targets;
this.afterNode = beforeNode;
setToolTipText(LanguageBundle.getString("in_equipMoveDownMenuDesc")); //$NON-NLS-1$
setIcon(Icons.Down16.getImageIcon());
setEnabled(!targets.isEmpty());
addActionListener(this);
}
/**
* Action to move the current item up in the current container
*/
@Override
public void actionPerformed(ActionEvent e)
{
EquipmentSetFacade equipSet
= character.getEquipmentSetRef().get();
for (EquipNode equipNode : targets)
{
equipSet.moveEquipment(equipNode, 1);
}
}
}
/**
* Menu item for moving the selected equipment up a step in their container.
*/
private class SortEquipMenuItem extends JMenuItem implements ActionListener
{
private final CharacterFacade character;
private final List<EquipNode> targets;
SortEquipMenuItem(CharacterFacade character, List<EquipNode> targets)
{
super(LanguageBundle.getString("in_equipSortAscMenuCommand")); //$NON-NLS-1$
this.character = character;
this.targets = targets;
setToolTipText(LanguageBundle.getString("in_equipSortAscMenuDesc")); //$NON-NLS-1$
setIcon(Icons.FForward16.getImageIcon());
setEnabled(!targets.isEmpty());
addActionListener(this);
}
/**
* Action to move the current item up in the current container
*/
@Override
public void actionPerformed(ActionEvent e)
{
EquipmentSetFacade equipSet
= character.getEquipmentSetRef().get();
for (EquipNode equipNode : targets)
{
equipSet.sortEquipment(equipNode);
}
}
}
}