/*
* SpellsPreparedTab.java
* Copyright 2011 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 Oct 1, 2011, 10:09:27 PM
*/
package pcgen.gui2.tabs.spells;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.tree.TreePath;
import org.apache.commons.lang3.StringUtils;
import pcgen.facade.core.CharacterFacade;
import pcgen.facade.core.ClassFacade;
import pcgen.facade.core.SpellFacade;
import pcgen.facade.core.SpellSupportFacade.SpellNode;
import pcgen.facade.core.SpellSupportFacade.SuperNode;
import pcgen.facade.util.ListFacade;
import pcgen.gui2.filter.Filter;
import pcgen.gui2.filter.FilterBar;
import pcgen.gui2.filter.FilterButton;
import pcgen.gui2.filter.FilterUtilities;
import pcgen.gui2.filter.FilteredTreeViewTable;
import pcgen.gui2.filter.SearchFilterPanel;
import pcgen.gui2.tabs.CharacterInfoTab;
import pcgen.gui2.tabs.TabTitle;
import pcgen.gui2.tools.FlippingSplitPane;
import pcgen.gui2.tools.Icons;
import pcgen.gui2.tools.InfoPane;
import pcgen.gui2.util.JTreeViewTable;
import pcgen.gui2.util.table.SortableTableModel;
import pcgen.gui2.util.table.SortableTableRowSorter;
import pcgen.gui2.util.treeview.TreeViewModel;
import pcgen.system.LanguageBundle;
import pcgen.util.enumeration.Tab;
/**
*
* @author Connor Petty <cpmeister@users.sourceforge.net>
*/
@SuppressWarnings("serial")
public class SpellsPreparedTab extends FlippingSplitPane implements CharacterInfoTab
{
private final TabTitle tabTitle = new TabTitle(Tab.PREPARED_SPELLS);
private final FilteredTreeViewTable<CharacterFacade, SuperNode> availableTable;
private final JTreeViewTable<SuperNode> selectedTable;
private final QualifiedSpellTreeCellRenderer spellRenderer;
private final JButton addMMSpellButton;
private final JButton addSpellButton;
private final JButton removeSpellButton;
private final FilterButton<CharacterFacade, SuperNode> qFilterButton;
private final JButton addSpellListButton;
private final JButton removeSpellListButton;
private final JCheckBox slotsBox;
private final JTextField spellListField;
private final InfoPane spellsPane;
private final InfoPane classPane;
public SpellsPreparedTab()
{
super("SpellsPrepared");
this.availableTable = new FilteredTreeViewTable<>();
this.selectedTable = new JTreeViewTable<SuperNode>(){
@Override
public void setTreeViewModel(TreeViewModel<SuperNode> viewModel)
{
super.setTreeViewModel(viewModel);
sortModel();
}
};
this.spellRenderer = new QualifiedSpellTreeCellRenderer();
this.addMMSpellButton = new JButton();
this.addSpellButton = new JButton();
this.removeSpellButton = new JButton();
this.qFilterButton = new FilterButton<>("SpellPreparedQualified");
this.addSpellListButton = new JButton();
this.removeSpellListButton = new JButton();
this.slotsBox = new JCheckBox();
this.spellListField = new JTextField();
this.spellsPane = new InfoPane(LanguageBundle.getString("InfoSpells.spell.info"));
this.classPane = new InfoPane(LanguageBundle.getString("InfoSpells.class.info"));
initComponents();
}
private void initComponents()
{
availableTable.setTreeCellRenderer(spellRenderer);
selectedTable.setTreeCellRenderer(spellRenderer);
selectedTable.setRowSorter(new SortableTableRowSorter(){
@Override
public SortableTableModel getModel()
{
return (SortableTableModel) selectedTable.getModel();
}
});
selectedTable.getRowSorter().toggleSortOrder(0);
FilterBar<CharacterFacade, SuperNode> filterBar = new FilterBar<>();
filterBar.addDisplayableFilter(new SearchFilterPanel());
qFilterButton.setText(LanguageBundle.getString("in_igQualFilter")); //$NON-NLS-1$
filterBar.addDisplayableFilter(qFilterButton);
FlippingSplitPane upperPane = new FlippingSplitPane("SpellsPreparedTop");
JPanel availPanel = FilterUtilities.configureFilteredTreeViewPane(availableTable, filterBar);
Box box = Box.createVerticalBox();
box.add(Box.createVerticalStrut(5));
{
Box hbox = Box.createHorizontalBox();
addMMSpellButton.setHorizontalTextPosition(SwingConstants.LEADING);
hbox.add(addMMSpellButton);
box.add(hbox);
}
box.add(Box.createVerticalStrut(2));
{
Box hbox = Box.createHorizontalBox();
hbox.add(Box.createHorizontalStrut(5));
hbox.add(slotsBox);
hbox.add(Box.createHorizontalGlue());
hbox.add(Box.createHorizontalStrut(10));
hbox.add(addSpellButton);
hbox.add(Box.createHorizontalStrut(5));
box.add(hbox);
}
box.add(Box.createVerticalStrut(5));
availPanel.add(box, BorderLayout.SOUTH);
upperPane.setLeftComponent(availPanel);
box = Box.createVerticalBox();
box.add(new JScrollPane(selectedTable));
box.add(Box.createVerticalStrut(4));
{
Box hbox = Box.createHorizontalBox();
hbox.add(Box.createHorizontalStrut(5));
hbox.add(removeSpellButton);
hbox.add(Box.createHorizontalStrut(10));
hbox.add(new JLabel(LanguageBundle.getString("InfoPreparedSpells.preparedList")));
hbox.add(Box.createHorizontalStrut(3));
hbox.add(spellListField);
hbox.add(Box.createHorizontalStrut(3));
hbox.add(addSpellListButton);
hbox.add(Box.createHorizontalStrut(3));
hbox.add(removeSpellListButton);
hbox.add(Box.createHorizontalStrut(5));
box.add(hbox);
}
box.add(Box.createVerticalStrut(5));
upperPane.setRightComponent(box);
upperPane.setResizeWeight(0);
setTopComponent(upperPane);
FlippingSplitPane bottomPane = new FlippingSplitPane("SpellsPreparedBottom");
bottomPane.setLeftComponent(spellsPane);
bottomPane.setRightComponent(classPane);
setBottomComponent(bottomPane);
setOrientation(VERTICAL_SPLIT);
}
@Override
public ModelMap createModels(CharacterFacade character)
{
ModelMap models = new ModelMap();
models.put(TreeViewModelHandler.class, new TreeViewModelHandler(character));
models.put(AddMMSpellAction.class, new AddMMSpellAction(character));
models.put(AddSpellAction.class, new AddSpellAction(character));
models.put(RemoveSpellAction.class, new RemoveSpellAction(character));
models.put(AddSpellListAction.class, new AddSpellListAction(character));
models.put(RemoveSpellListAction.class, new RemoveSpellListAction(character));
models.put(UseHigherSlotsAction.class, new UseHigherSlotsAction(character));
models.put(SpellInfoHandler.class, new SpellInfoHandler(character, availableTable,
selectedTable, spellsPane));
models.put(ClassInfoHandler.class, new ClassInfoHandler(character, availableTable,
selectedTable, classPane));
models.put(SpellFilterHandler.class, new SpellFilterHandler(character));
return models;
}
@Override
public void restoreModels(ModelMap models)
{
models.get(SpellFilterHandler.class).install();
models.get(TreeViewModelHandler.class).install();
models.get(SpellInfoHandler.class).install();
models.get(ClassInfoHandler.class).install();
models.get(AddSpellAction.class).install();
models.get(RemoveSpellAction.class).install();
addMMSpellButton.setAction(models.get(AddMMSpellAction.class));
addSpellListButton.setAction(models.get(AddSpellListAction.class));
removeSpellListButton.setAction(models.get(RemoveSpellListAction.class));
models.get(UseHigherSlotsAction.class).install();
}
@Override
public void storeModels(ModelMap models)
{
models.get(SpellInfoHandler.class).uninstall();
models.get(ClassInfoHandler.class).uninstall();
models.get(AddSpellAction.class).uninstall();
models.get(RemoveSpellAction.class).uninstall();
models.get(TreeViewModelHandler.class).uninstall();
}
@Override
public TabTitle getTabTitle()
{
return tabTitle;
}
/**
* Identify the current spell list, being the spell list that spell should
* be added to. If no lists exist then a default one will be created.
*
* @param character The character qwe are checking for.
* @return The name of the 'current' spell list.
*/
String getCurrentSpellListName(CharacterFacade character)
{
String spellList = "";
Object selectedObject = selectedTable.getSelectedObject();
if (selectedObject != null)
{
if (selectedObject instanceof SpellNode)
{
spellList
= ((SpellNode) selectedObject).getRootNode()
.toString();
}
else
{
JTree tree = selectedTable.getTree();
TreePath path = tree.getSelectionPath();
while (path.getParentPath() != null && (path.getParentPath().getParentPath() != null))
{
path = path.getParentPath();
}
spellList = path.getLastPathComponent().toString();
}
}
if (StringUtils.isEmpty(spellList))
{
spellList = spellListField.getText();
}
if (StringUtils.isEmpty(spellList))
{
ListFacade<?> data = selectedTable.getTreeViewModel().getDataModel();
if (!data.isEmpty())
{
Object firstElem = data.getElementAt(0);
if (firstElem instanceof SpellNode)
{
spellList = ((SpellNode) firstElem).getRootNode().toString();
}
}
}
if (StringUtils.isEmpty(spellList))
{
// No lists exist, so create a default one!
spellList = "Prepared Spells";
character.getSpellSupport().addSpellList(spellList);
}
return spellList;
}
private class AddMMSpellAction extends AbstractAction
{
private CharacterFacade character;
public AddMMSpellAction(CharacterFacade character)
{
this.character = character;
String label
= character.getDataSet().getGameMode()
.getAddWithMetamagicMessage();
if (StringUtils.isEmpty(label))
{
label
= LanguageBundle
.getString("InfoSpells.add.with.metamagic");
}
putValue(NAME, label);
putValue(SMALL_ICON, Icons.Forward16.getImageIcon());
}
@Override
public void actionPerformed(ActionEvent e)
{
List<?> data = availableTable.getSelectedData();
for (Object object : data)
{
if (object instanceof SpellNode)
{
String spellList = getCurrentSpellListName(character);
character.getSpellSupport().addPreparedSpell(
(SpellNode) object, spellList, true);
}
}
}
}
private class AddSpellAction extends AbstractAction
{
private CharacterFacade character;
public AddSpellAction(CharacterFacade character)
{
this.character = character;
putValue(SMALL_ICON, Icons.Forward16.getImageIcon());
}
@Override
public void actionPerformed(ActionEvent e)
{
List<?> data = availableTable.getSelectedData();
String spellList = getCurrentSpellListName(character);
for (Object object : data)
{
if (object instanceof SpellNode)
{
character.getSpellSupport().addPreparedSpell(
(SpellNode) object, spellList, false);
}
}
}
public void install()
{
availableTable.addActionListener(this);
addSpellButton.setAction(this);
}
public void uninstall()
{
availableTable.removeActionListener(this);
}
}
private class RemoveSpellAction extends AbstractAction
{
private CharacterFacade character;
public RemoveSpellAction(CharacterFacade character)
{
this.character = character;
putValue(SMALL_ICON, Icons.Back16.getImageIcon());
}
@Override
public void actionPerformed(ActionEvent e)
{
List<?> data = selectedTable.getSelectedData();
for (Object object : data)
{
if (object instanceof SpellNode)
{
SpellNode spellNode = (SpellNode) object;
character.getSpellSupport().removePreparedSpell(spellNode,
spellNode.getRootNode().toString());
}
}
}
public void install()
{
selectedTable.addActionListener(this);
removeSpellButton.setAction(this);
}
public void uninstall()
{
selectedTable.removeActionListener(this);
}
}
private class UseHigherSlotsAction extends AbstractAction
{
private CharacterFacade character;
public UseHigherSlotsAction(CharacterFacade character)
{
super(LanguageBundle.getString("InfoPreparedSpells.canUseHigherSlots"));
this.character = character;
}
@Override
public void actionPerformed(ActionEvent e)
{
character.getSpellSupport().setUseHigherPreppedSlots(slotsBox.isSelected());
}
public void install()
{
slotsBox.setAction(this);
slotsBox.setSelected(character.getSpellSupport().isUseHigherPreppedSlots());
}
}
private class AddSpellListAction extends AbstractAction
{
private CharacterFacade character;
public AddSpellListAction(CharacterFacade character)
{
super(LanguageBundle.getString("InfoSpells.add"));
this.character = character;
}
@Override
public void actionPerformed(ActionEvent e)
{
character.getSpellSupport().addSpellList(spellListField.getText());
}
}
private class RemoveSpellListAction extends AbstractAction
{
private CharacterFacade character;
public RemoveSpellListAction(CharacterFacade character)
{
super(LanguageBundle.getString("InfoSpells.delete"));
this.character = character;
}
@Override
public void actionPerformed(ActionEvent e)
{
character.getSpellSupport().removeSpellList(spellListField.getText());
}
}
private class TreeViewModelHandler
{
private SpellTreeViewModel availableModel;
private SpellTreeViewModel selectedModel;
private CharacterFacade character;
public TreeViewModelHandler(CharacterFacade character)
{
this.character = character;
availableModel = new SpellTreeViewModel(character.getSpellSupport().getKnownSpellNodes(),
false, "SpellsPrepAva", character.getInfoFactory());
selectedModel = new SpellTreeViewModel(character.getSpellSupport().getPreparedSpellNodes(),
true, "SpellsPrepSel", character.getInfoFactory());
}
public void install()
{
spellRenderer.setCharacter(character);
availableTable.setTreeViewModel(availableModel);
selectedTable.setTreeViewModel(selectedModel);
}
public void uninstall()
{
spellRenderer.setCharacter(null);
}
}
private class SpellFilterHandler implements Filter<CharacterFacade, SuperNode>
{
private final CharacterFacade character;
public SpellFilterHandler(CharacterFacade character)
{
this.character = character;
}
public void install()
{
qFilterButton.setFilter(this);
}
@Override
public boolean accept(CharacterFacade context, SuperNode element)
{
if (element instanceof SpellNode)
{
SpellNode spellNode = (SpellNode) element;
SpellFacade spell = spellNode.getSpell();
ClassFacade pcClass = spellNode.getSpellcastingClass();
return character.isQualifiedFor(spell, pcClass);
}
return true;
}
}
}