/*
* SpellBooksTab.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:50 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.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
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;
import pcgen.facade.core.SpellSupportFacade.RootNode;
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.tabs.models.CharacterComboBoxModel;
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 SpellBooksTab extends FlippingSplitPane implements CharacterInfoTab
{
private final TabTitle tabTitle = new TabTitle(Tab.SPELLBOOKS);
private final FilteredTreeViewTable<CharacterFacade, SuperNode> availableTable;
private final JTreeViewTable<SuperNode> selectedTable;
private final QualifiedSpellTreeCellRenderer spellRenderer;
private final JButton addButton;
private final JButton removeButton;
private final FilterButton<CharacterFacade, SuperNode> qFilterButton;
private final InfoPane spellsPane;
private final InfoPane classPane;
private final JComboBox defaultBookCombo;
public SpellBooksTab()
{
super("SpellBooks");
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.addButton = new JButton();
this.removeButton = new JButton();
this.qFilterButton = new FilterButton<>("SpellBooksQualified");
this.spellsPane = new InfoPane(LanguageBundle.getString("InfoSpells.spell.info"));
this.classPane = new InfoPane(LanguageBundle.getString("InfoSpells.class.info"));
this.defaultBookCombo = new JComboBox();
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("SpellBooksTop");
JPanel availPanel = FilterUtilities.configureFilteredTreeViewPane(availableTable, filterBar);
Box box = Box.createVerticalBox();
box.add(Box.createVerticalStrut(5));
{
Box hbox = Box.createHorizontalBox();
hbox.add(Box.createHorizontalStrut(5));
hbox.add(new JLabel(LanguageBundle.getString("InfoSpells.set.auto.book")));
hbox.add(Box.createHorizontalGlue());
box.add(hbox);
}
box.add(Box.createVerticalStrut(5));
{
Box hbox = Box.createHorizontalBox();
hbox.add(Box.createHorizontalStrut(5));
hbox.add(defaultBookCombo);
hbox.add(Box.createHorizontalGlue());
hbox.add(Box.createHorizontalStrut(5));
hbox.add(addButton);
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(5));
{
Box hbox = Box.createHorizontalBox();
hbox.add(Box.createHorizontalStrut(5));
hbox.add(removeButton);
hbox.add(Box.createHorizontalGlue());
box.add(hbox);
}
box.add(Box.createVerticalStrut(5));
upperPane.setRightComponent(box);
upperPane.setResizeWeight(0);
setTopComponent(upperPane);
FlippingSplitPane bottomPane = new FlippingSplitPane("SpellBooksBottom");
bottomPane.setLeftComponent(spellsPane);
bottomPane.setRightComponent(classPane);
setBottomComponent(bottomPane);
setOrientation(VERTICAL_SPLIT);
}
@Override
public ModelMap createModels(final CharacterFacade character)
{
ModelMap models = new ModelMap();
models.put(TreeViewModelHandler.class, new TreeViewModelHandler(character));
models.put(AddSpellAction.class, new AddSpellAction(character));
models.put(RemoveSpellAction.class, new RemoveSpellAction(character));
models.put(SpellInfoHandler.class, new SpellInfoHandler(character, availableTable,
selectedTable, spellsPane));
models.put(ClassInfoHandler.class, new ClassInfoHandler(character, availableTable,
selectedTable, classPane));
models.put(SpellBookModel.class, new SpellBookModel(character));
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();
defaultBookCombo.setModel(models.get(SpellBookModel.class));
}
@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 book, being the spell book that spells should
* be added to. If no books exist then return an empty string.
*
* @return The name of the 'current' spell book, or empty string if none
* exist.
*/
String getCurrentSpellBookName()
{
String spellList = "";
Object selectedObject = selectedTable.getSelectedObject();
if (selectedObject != null)
{
if (selectedObject instanceof SpellNode)
{
spellList = ((SpellNode) selectedObject).getRootNode().getName();
}
else if (selectedObject instanceof RootNode)
{
spellList = ((RootNode) selectedObject).getName();
}
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))
{
ListFacade<?> data = selectedTable.getTreeViewModel().getDataModel();
if (!data.isEmpty())
{
Object firstElem = data.getElementAt(0);
if (firstElem instanceof SpellNode)
{
spellList = ((SpellNode) firstElem).getRootNode().getName();
}
}
}
return spellList;
}
private class SpellBookModel extends CharacterComboBoxModel<String>
{
private final SpellSupportFacade spellSupport;
public SpellBookModel(CharacterFacade character)
{
this.spellSupport = character.getSpellSupport();
setListFacade(spellSupport.getSpellbooks());
setReference(spellSupport.getDefaultSpellBookRef());
}
@Override
public void setSelectedItem(Object anItem)
{
spellSupport.setDefaultSpellBook((String) anItem);
}
}
private class AddSpellAction extends AbstractAction
{
private final 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 bookname = getCurrentSpellBookName();
for (Object object : data)
{
if (object instanceof SpellNode)
{
character.getSpellSupport().addToSpellBook(
(SpellNode) object, bookname);
}
}
}
public void install()
{
availableTable.addActionListener(this);
addButton.setAction(this);
}
public void uninstall()
{
availableTable.removeActionListener(this);
}
}
private class RemoveSpellAction extends AbstractAction
{
private final 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 node = (SpellNode) object;
character.getSpellSupport().removeFromSpellBook(node,
node.getRootNode().getName());
}
}
}
public void install()
{
selectedTable.addActionListener(this);
removeButton.setAction(this);
}
public void uninstall()
{
selectedTable.removeActionListener(this);
}
}
private class TreeViewModelHandler
{
private final SpellTreeViewModel availableModel;
private final SpellTreeViewModel selectedModel;
private final CharacterFacade character;
public TreeViewModelHandler(CharacterFacade character)
{
this.character = character;
availableModel = new SpellTreeViewModel(character.getSpellSupport().getKnownSpellNodes(), false, "SpellBooksAva", character.getInfoFactory());
selectedModel = new SpellTreeViewModel(character.getSpellSupport().getBookSpellNodes(), true, "SpellBooksSel", 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;
}
}
}