/*
* TempBonusInfoTab.java
* Copyright James Dempsey, 2012
*
* 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 08/06/2012 7:42:35 PM
*
* $Id$
*/
package pcgen.gui2.tabs;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import pcgen.facade.core.CharacterFacade;
import pcgen.facade.core.InfoFacade;
import pcgen.facade.core.InfoFactory;
import pcgen.facade.core.TempBonusFacade;
import pcgen.facade.util.DefaultListFacade;
import pcgen.facade.util.ListFacade;
import pcgen.facade.util.event.ListEvent;
import pcgen.facade.util.event.ListListener;
import pcgen.gui2.UIPropertyContext;
import pcgen.gui2.filter.Filter;
import pcgen.gui2.filter.FilterBar;
import pcgen.gui2.filter.FilteredListFacade;
import pcgen.gui2.filter.FilteredTreeViewTable;
import pcgen.gui2.filter.SearchFilterPanel;
import pcgen.gui2.tabs.models.CharacterTreeCellRenderer;
import pcgen.gui2.tabs.models.CharacterTreeCellRenderer.Handler;
import pcgen.gui2.tools.FlippingSplitPane;
import pcgen.gui2.tools.Icons;
import pcgen.gui2.tools.InfoPane;
import pcgen.gui2.util.FontManipulation;
import pcgen.gui2.util.treeview.DataView;
import pcgen.gui2.util.treeview.DataViewColumn;
import pcgen.gui2.util.treeview.DefaultDataViewColumn;
import pcgen.gui2.util.treeview.TreeView;
import pcgen.gui2.util.treeview.TreeViewModel;
import pcgen.gui2.util.treeview.TreeViewPath;
import pcgen.system.LanguageBundle;
import pcgen.util.enumeration.Tab;
/**
* The Class {@code TempBonusInfoTab} allows the user to select which
* temporary bonus should be applied to their character.
*
* <br>
* -0700 (Sat, 17 May 2014) $
*
* @author James Dempsey <jdempsey@users.sourceforge.net>
*/
public class TempBonusInfoTab extends FlippingSplitPane implements CharacterInfoTab
{
/**
* Version for serialisation.
*/
private static final long serialVersionUID = 4521237435574462482L;
private final TabTitle tabTitle = new TabTitle(Tab.TEMPBONUS);
private final FilteredTreeViewTable<CharacterFacade, TempBonusFacade> availableTable;
private final FilteredTreeViewTable<CharacterFacade, TempBonusFacade> selectedTable;
private final JButton addButton;
private final JButton removeButton;
private final InfoPane infoPane;
private final TempBonusRenderer tempBonusRenderer;
/**
* Create a new instance of TemporaryBonusInfoTab.
*/
public TempBonusInfoTab()
{
super("TempBonus");
this.availableTable = new FilteredTreeViewTable<>();
this.selectedTable = new FilteredTreeViewTable<>();
this.addButton = new JButton();
this.removeButton = new JButton();
this.infoPane = new InfoPane(LanguageBundle.getString("in_InfoTempMod")); //$NON-NLS-1$
this.tempBonusRenderer = new TempBonusRenderer();
initComponents();
}
private void initComponents()
{
FlippingSplitPane topPane = new FlippingSplitPane("TempBonusTop");
setTopComponent(topPane);
setOrientation(VERTICAL_SPLIT);
JPanel availPanel = new JPanel(new BorderLayout());
FilterBar<CharacterFacade, TempBonusFacade> bar = new FilterBar<>();
bar.addDisplayableFilter(new SearchFilterPanel());
availPanel.add(bar, BorderLayout.NORTH);
availableTable.setDisplayableFilter(bar);
availableTable.setTreeCellRenderer(tempBonusRenderer);
availPanel.add(new JScrollPane(availableTable), BorderLayout.CENTER);
Box box = Box.createHorizontalBox();
box.add(Box.createHorizontalGlue());
addButton.setHorizontalTextPosition(SwingConstants.LEADING);
box.add(addButton);
box.add(Box.createHorizontalStrut(5));
box.setBorder(new EmptyBorder(0, 0, 5, 0));
availPanel.add(box, BorderLayout.SOUTH);
topPane.setLeftComponent(availPanel);
JPanel selPanel = new JPanel(new BorderLayout());
FilterBar<CharacterFacade, TempBonusFacade> filterBar = new FilterBar<>();
filterBar.addDisplayableFilter(new SearchFilterPanel());
selectedTable.setDisplayableFilter(filterBar);
selectedTable.setTreeCellRenderer(tempBonusRenderer);
selPanel.add(new JScrollPane(selectedTable), BorderLayout.CENTER);
box = Box.createHorizontalBox();
box.add(Box.createHorizontalStrut(5));
box.add(removeButton);
box.add(Box.createHorizontalGlue());
box.setBorder(new EmptyBorder(0, 0, 5, 0));
selPanel.add(box, BorderLayout.SOUTH);
topPane.setRightComponent(selPanel);
setBottomComponent(infoPane);
setResizeWeight(0.75);
}
@Override
public ModelMap createModels(CharacterFacade character)
{
ModelMap models = new ModelMap();
models.put(TreeViewModelHandler.class, new TreeViewModelHandler(character));
models.put(InfoHandler.class, new InfoHandler(character));
models.put(AddAction.class, new AddAction(character));
models.put(RemoveAction.class, new RemoveAction(character));
models.put(Handler.class, tempBonusRenderer.createHandler(character));
return models;
}
@Override
public void restoreModels(ModelMap models)
{
models.get(Handler.class).install();
models.get(TreeViewModelHandler.class).install();
models.get(InfoHandler.class).install();
models.get(AddAction.class).install();
models.get(RemoveAction.class).install();
}
@Override
public void storeModels(ModelMap models)
{
models.get(InfoHandler.class).uninstall();
models.get(AddAction.class).uninstall();
models.get(RemoveAction.class).uninstall();
models.get(Handler.class).uninstall();
}
@Override
public TabTitle getTabTitle()
{
return tabTitle;
}
private static class TempBonusRenderer extends CharacterTreeCellRenderer
{
/**
* Version for serialisation.
*/
private static final long serialVersionUID = -9006249573217208478L;
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row, boolean focus)
{
Object obj = ((DefaultMutableTreeNode) value).getUserObject();
if ("".equals(obj)) //$NON-NLS-1$
{
obj = LanguageBundle.getString("in_none"); //$NON-NLS-1$
}
super.getTreeCellRendererComponent(tree, obj, sel, expanded, leaf, row, focus);
if (value instanceof TempBonusFacade && !character.isQualifiedFor((TempBonusFacade) value))
{
setForeground(UIPropertyContext.getNotQualifiedColor());
}
if (value instanceof InfoFacade && ((InfoFacade) value).isNamePI())
{
setFont(FontManipulation.bold_italic(getFont()));
}
else
{
setFont(FontManipulation.plain(getFont()));
}
return this;
}
}
private class InfoHandler implements ListSelectionListener
{
private CharacterFacade character;
private String text;
public InfoHandler(CharacterFacade character)
{
this.character = character;
this.text = ""; //$NON-NLS-1$
}
public void install()
{
availableTable.getSelectionModel().addListSelectionListener(this);
selectedTable.getSelectionModel().addListSelectionListener(this);
infoPane.setText(text);
}
public void uninstall()
{
availableTable.getSelectionModel().removeListSelectionListener(this);
selectedTable.getSelectionModel().removeListSelectionListener(this);
}
@Override
public void valueChanged(ListSelectionEvent e)
{
if (!e.getValueIsAdjusting())
{
Object obj = null;
if (e.getSource() == availableTable.getSelectionModel())
{
int selectedRow = availableTable.getSelectedRow();
if (selectedRow != -1)
{
obj = availableTable.getModel().getValueAt(selectedRow, 0);
}
}
else
{
int selectedRow = selectedTable.getSelectedRow();
if (selectedRow != -1)
{
obj = selectedTable.getModel().getValueAt(selectedRow, 0);
}
}
if (obj instanceof TempBonusFacade)
{
text = character.getInfoFactory().getHTMLInfo((TempBonusFacade) obj);
infoPane.setText(text);
}
}
}
}
private class AddAction extends AbstractAction
{
/**
* Version for serialisation.
*/
private static final long serialVersionUID = -6640460398947215666L;
private CharacterFacade character;
public AddAction(CharacterFacade character)
{
super(LanguageBundle.getString("in_itmInitCompAppBonTitle")); //$NON-NLS-1$
this.character = character;
putValue(SMALL_ICON, Icons.Forward16.getImageIcon());
}
@Override
public void actionPerformed(ActionEvent e)
{
List<Object> data = availableTable.getSelectedData();
for (Object object : data)
{
if (object instanceof TempBonusFacade)
{
character.addTempBonus((TempBonusFacade) object);
return;
}
}
}
public void install()
{
availableTable.addActionListener(this);
addButton.setAction(this);
}
public void uninstall()
{
availableTable.removeActionListener(this);
}
}
private class RemoveAction extends AbstractAction
{
/**
* Version for serialisation.
*/
private static final long serialVersionUID = 2922387838116495051L;
private CharacterFacade character;
public RemoveAction(CharacterFacade character)
{
super(LanguageBundle.getString("in_itmInitCompRemoveButTitle")); //$NON-NLS-1$
this.character = character;
putValue(SMALL_ICON, Icons.Back16.getImageIcon());
}
@Override
public void actionPerformed(ActionEvent e)
{
List<Object> data = selectedTable.getSelectedData();
for (Object object : data)
{
if (object instanceof TempBonusFacade)
{
character.removeTempBonus((TempBonusFacade) object);
return;
}
}
}
public void install()
{
selectedTable.addActionListener(this);
removeButton.setAction(this);
}
public void uninstall()
{
selectedTable.removeActionListener(this);
}
}
private class TreeViewModelHandler
{
private final TempBonusTreeViewModel availableModel;
private final TempBonusTreeViewModel selectedModel;
public TreeViewModelHandler(CharacterFacade character)
{
availableModel = new TempBonusTreeViewModel(character, true);
selectedModel = new TempBonusTreeViewModel(character, false);
}
public void install()
{
availableModel.install();
availableTable.setTreeViewModel(availableModel);
selectedModel.install();
selectedTable.setTreeViewModel(selectedModel);
}
}
private static class TempBonusTreeViewModel
implements TreeViewModel<TempBonusFacade>, DataView<TempBonusFacade>,
Filter<CharacterFacade, TempBonusFacade>, ListListener<TempBonusFacade>
{
private static final DefaultListFacade<? extends TreeView<TempBonusFacade>> treeViews
= new DefaultListFacade<TreeView<TempBonusFacade>>(Arrays.asList(TempBonusTreeView.values()));
private final List<DefaultDataViewColumn> columns;
private final CharacterFacade character;
private final InfoFactory infoFactory;
private final boolean isAvailModel;
private FilteredListFacade<CharacterFacade, TempBonusFacade> tempBonuses;
public TempBonusTreeViewModel(CharacterFacade character, boolean isAvailModel)
{
this.character = character;
this.infoFactory = character.getInfoFactory();
this.isAvailModel = isAvailModel;
if (isAvailModel)
{
tempBonuses = new FilteredListFacade<>();
tempBonuses.setContext(character);
tempBonuses.setFilter(this);
tempBonuses.setDelegate(character.getAvailableTempBonuses());
character.getAvailableTempBonuses().addListListener(this);
columns = Arrays.asList(new DefaultDataViewColumn("in_itmFrom", String.class, true), //$NON-NLS-1$
new DefaultDataViewColumn("in_itmTarget", String.class, true), //$NON-NLS-1$
new DefaultDataViewColumn("in_descrip", String.class, false), //$NON-NLS-1$
new DefaultDataViewColumn("in_source", String.class, false)); //$NON-NLS-1$
}
else
{
tempBonuses = null;
columns = Arrays.asList(new DefaultDataViewColumn("in_itmFrom", String.class, false), //$NON-NLS-1$
new DefaultDataViewColumn("in_itmTarget", String.class, true), //$NON-NLS-1$
new DefaultDataViewColumn("in_descrip", String.class, false), //$NON-NLS-1$
new DefaultDataViewColumn("in_source", String.class, false)); //$NON-NLS-1$
}
}
public void install()
{
for (TempBonusTreeView tbTreeView : TempBonusTreeView.values())
{
tbTreeView.setInfoFactory(infoFactory);
}
}
@Override
public ListFacade<? extends TreeView<TempBonusFacade>> getTreeViews()
{
return treeViews;
}
@Override
public int getDefaultTreeViewIndex()
{
return isAvailModel ? 1 : 0;
}
@Override
public DataView<TempBonusFacade> getDataView()
{
return this;
}
@Override
public ListFacade<TempBonusFacade> getDataModel()
{
if (isAvailModel)
{
return tempBonuses;
}
else
{
return character.getTempBonuses();
}
}
@Override
public Object getData(TempBonusFacade obj, int column)
{
switch(column){
case 0:
return obj.getOriginType();
case 1:
return infoFactory.getTempBonusTarget(obj);
case 2:
return infoFactory.getDescription(obj);
case 3:
return obj.getSource();
default:
return null;
}
}
@Override
public void setData(Object value, TempBonusFacade element, int column)
{
}
@Override
public List<? extends DataViewColumn> getDataColumns()
{
return columns;
}
@Override
public void elementAdded(ListEvent<TempBonusFacade> e)
{
tempBonuses.refilter();
}
@Override
public void elementRemoved(ListEvent<TempBonusFacade> e)
{
tempBonuses.refilter();
}
@Override
public void elementsChanged(ListEvent<TempBonusFacade> e)
{
tempBonuses.refilter();
}
@Override
public void elementModified(ListEvent<TempBonusFacade> e)
{
tempBonuses.refilter();
}
@Override
public boolean accept(CharacterFacade context, TempBonusFacade element)
{
return !context.getTempBonuses().containsElement(element);
}
@Override
public String getPrefsKey()
{
return isAvailModel ? "TempModsTreeAvail" : "TempModsTreeSelected"; //$NON-NLS-1$//$NON-NLS-2$
}
}
private enum TempBonusTreeView implements TreeView<TempBonusFacade>
{
NAME("in_nameLabel"), //$NON-NLS-1$
ORIGIN_NAME("in_itmOriginName"), //$NON-NLS-1$
SOURCE_NAME("in_sourceName"), //$NON-NLS-1$
TARGET_NAME("in_itmTargetName"); //$NON-NLS-1$
private final String name;
private InfoFactory infoFactory;
private TempBonusTreeView(String name)
{
this.name = LanguageBundle.getString(name);
}
/**
* @param factory The InfoFactory for the character ebing displayed.
*/
public void setInfoFactory(InfoFactory factory)
{
this.infoFactory = factory;
}
@Override
public String getViewName()
{
return name;
}
@Override
public List<TreeViewPath<TempBonusFacade>> getPaths(TempBonusFacade bonus)
{
switch (this)
{
case TARGET_NAME:
if (infoFactory != null)
{
return Collections.singletonList(new TreeViewPath<>(bonus,
infoFactory.getTempBonusTarget(bonus)));
}
// No info factory? Treat as a name
case NAME:
return Collections.singletonList(new TreeViewPath<>(bonus));
case ORIGIN_NAME:
return Collections.singletonList(new TreeViewPath<>(bonus,
bonus.getOriginType()));
case SOURCE_NAME:
return Collections.singletonList(new TreeViewPath<>(bonus,
bonus.getSourceForNodeDisplay()));
default:
throw new InternalError();
}
}
}
}