/*
* TemplateInfoTab.java
* Copyright 2010 (C) 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 Sep 13, 2010, 6:22:26 PM
*/
package pcgen.gui2.tabs;
import java.awt.BorderLayout;
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.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import pcgen.facade.core.CharacterFacade;
import pcgen.facade.core.InfoFactory;
import pcgen.facade.core.TemplateFacade;
import pcgen.facade.util.event.ListEvent;
import pcgen.facade.util.event.ListListener;
import pcgen.facade.util.DefaultListFacade;
import pcgen.facade.util.ListFacade;
import pcgen.gui2.filter.Filter;
import pcgen.gui2.filter.FilterBar;
import pcgen.gui2.filter.FilterButton;
import pcgen.gui2.filter.FilteredListFacade;
import pcgen.gui2.filter.FilteredTreeViewTable;
import pcgen.gui2.filter.SearchFilterPanel;
import pcgen.gui2.tabs.models.CharacterTreeCellRenderer.Handler;
import pcgen.gui2.tabs.models.QualifiedTreeCellRenderer;
import pcgen.gui2.tools.FlippingSplitPane;
import pcgen.gui2.tools.Icons;
import pcgen.gui2.tools.InfoPane;
import pcgen.gui2.util.treeview.CachedDataView;
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;
/**
* This component allows the user to manage a character's templates.
*
* @author Connor Petty <cpmeister@users.sourceforge.net>
*/
public class TemplateInfoTab extends FlippingSplitPane implements CharacterInfoTab
{
private final TabTitle tabTitle = new TabTitle(Tab.TEMPLATES);
private final FilteredTreeViewTable<CharacterFacade, TemplateFacade> availableTable;
private final FilteredTreeViewTable<CharacterFacade, TemplateFacade> selectedTable;
private final JButton addButton;
private final JButton removeButton;
private final InfoPane infoPane;
private final FilterButton<CharacterFacade, TemplateFacade> qFilterButton;
private final QualifiedTreeCellRenderer qualifiedRenderer;
public TemplateInfoTab()
{
super("Template");
this.availableTable = new FilteredTreeViewTable<>();
this.selectedTable = new FilteredTreeViewTable<>();
this.addButton = new JButton();
this.removeButton = new JButton();
this.infoPane = new InfoPane("in_irTemplateInfo"); //$NON-NLS-1$
this.qFilterButton = new FilterButton<>("TemplateQualified");
this.qualifiedRenderer = new QualifiedTreeCellRenderer();
initComponents();
}
private void initComponents()
{
FlippingSplitPane topPane = new FlippingSplitPane("TemplateTop");
setTopComponent(topPane);
setOrientation(VERTICAL_SPLIT);
JPanel availPanel = new JPanel(new BorderLayout());
FilterBar<CharacterFacade, TemplateFacade> bar = new FilterBar<>();
bar.addDisplayableFilter(new SearchFilterPanel());
qFilterButton.setText(LanguageBundle.getString("in_igQualFilter")); //$NON-NLS-1$
bar.addDisplayableFilter(qFilterButton);
availPanel.add(bar, BorderLayout.NORTH);
availableTable.setDisplayableFilter(bar);
availableTable.setTreeCellRenderer(qualifiedRenderer);
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, TemplateFacade> filterBar = new FilterBar<>();
filterBar.addDisplayableFilter(new SearchFilterPanel());
selectedTable.setDisplayableFilter(filterBar);
selectedTable.setTreeCellRenderer(qualifiedRenderer);
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, qualifiedRenderer.createHandler(character));
models.put(QualifiedFilterHandler.class, new QualifiedFilterHandler(character));
return models;
}
@Override
public void restoreModels(ModelMap models)
{
models.get(QualifiedFilterHandler.class).install();
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(TreeViewModelHandler.class).uninstall();
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 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 TemplateFacade)
{
text = character.getInfoFactory().getHTMLInfo((TemplateFacade) obj);
infoPane.setText(text);
}
}
}
}
private class AddAction extends AbstractAction
{
private CharacterFacade character;
public AddAction(CharacterFacade character)
{
super(LanguageBundle.getString("in_irAddTemplate")); //$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 TemplateFacade)
{
character.addTemplate((TemplateFacade) object);
return;
}
}
}
public void install()
{
availableTable.addActionListener(this);
addButton.setAction(this);
}
public void uninstall()
{
availableTable.removeActionListener(this);
}
}
private class RemoveAction extends AbstractAction
{
private CharacterFacade character;
public RemoveAction(CharacterFacade character)
{
super(LanguageBundle.getString("in_irRemoveTemplate")); //$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 TemplateFacade)
{
character.removeTemplate((TemplateFacade) object);
return;
}
}
}
public void install()
{
selectedTable.addActionListener(this);
removeButton.setAction(this);
}
public void uninstall()
{
selectedTable.removeActionListener(this);
}
}
private class QualifiedFilterHandler
{
private final Filter<CharacterFacade, TemplateFacade> qFilter = new Filter<CharacterFacade, TemplateFacade>()
{
@Override
public boolean accept(CharacterFacade context, TemplateFacade element)
{
return character.isQualifiedFor(element);
}
};
private final CharacterFacade character;
public QualifiedFilterHandler(CharacterFacade character)
{
this.character = character;
}
public void install()
{
qFilterButton.setFilter(qFilter);
}
}
private class TreeViewModelHandler
{
private final TemplateDataView availDataView;
private final TemplateDataView selDataView;
private final TemplateTreeViewModel availTreeView;
private final TemplateTreeViewModel selTreeView;
public TreeViewModelHandler(CharacterFacade character)
{
availDataView = new TemplateDataView(character, true);
selDataView = new TemplateDataView(character, false);
availTreeView = new TemplateTreeViewModel(character, true, availDataView);
selTreeView = new TemplateTreeViewModel(character, false, selDataView);
}
public void install()
{
availableTable.setTreeViewModel(availTreeView);
selectedTable.setTreeViewModel(selTreeView);
}
public void uninstall()
{
}
}
private class TemplateDataView extends CachedDataView<TemplateFacade>
{
private final List<DefaultDataViewColumn> columns;
private final InfoFactory infoFactory;
private final boolean isAvailModel;
public TemplateDataView(CharacterFacade character, boolean isAvailModel)
{
this.infoFactory = character.getInfoFactory();
this.isAvailModel = isAvailModel;
if (isAvailModel)
{
columns = Arrays.asList(new DefaultDataViewColumn("in_lvlAdj", String.class, true), //$NON-NLS-1$
new DefaultDataViewColumn("in_modifier", String.class, true), //$NON-NLS-1$
new DefaultDataViewColumn("in_preReqs", 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
{
columns = Arrays.asList(new DefaultDataViewColumn("in_lvlAdj", String.class, false), //$NON-NLS-1$
new DefaultDataViewColumn("in_modifier", String.class, false), //$NON-NLS-1$
new DefaultDataViewColumn("in_preReqs", String.class, false), //$NON-NLS-1$
new DefaultDataViewColumn("in_descrip", String.class, false), //$NON-NLS-1$
new DefaultDataViewColumn("in_source", String.class, false)); //$NON-NLS-1$
}
}
@Override
public List<? extends DataViewColumn> getDataColumns()
{
return columns;
}
@Override
public String getPrefsKey()
{
return isAvailModel ? "TemplateTreeAvail" : "TemplateTreeSelected"; //$NON-NLS-1$//$NON-NLS-2$
}
// @Override
// protected void refreshTableData()
// {
// if (isAvailModel)
// {
// availableTable.refreshModelData();
// }
// else
// {
// selectedTable.refreshModelData();
// }
// }
@Override
public Object getDataInternal(TemplateFacade obj, int column)
{
switch(column){
case 0:
return infoFactory.getLevelAdjustment(obj);
case 1:
return infoFactory.getModifier(obj);
case 2:
return infoFactory.getPreReqHTML(obj);
case 3:
return infoFactory.getDescription(obj);
case 4:
return obj.getSource();
default:
return null;
}
}
}
private static class TemplateTreeViewModel
implements TreeViewModel<TemplateFacade>, Filter<CharacterFacade, TemplateFacade>, ListListener<TemplateFacade>
{
private static final DefaultListFacade<? extends TreeView<TemplateFacade>> treeViews
= new DefaultListFacade<TreeView<TemplateFacade>>(Arrays.asList(TemplateTreeView.values()));
private final CharacterFacade character;
private final boolean isAvailModel;
private final TemplateDataView dataView;
private FilteredListFacade<CharacterFacade, TemplateFacade> templates;
public TemplateTreeViewModel(CharacterFacade character, boolean isAvailModel, TemplateDataView dataView)
{
this.character = character;
this.isAvailModel = isAvailModel;
this.dataView = dataView;
if (isAvailModel)
{
templates = new FilteredListFacade<>();
templates.setContext(character);
templates.setFilter(this);
templates.setDelegate(character.getDataSet().getTemplates());
character.getTemplates().addListListener(this);
}
else
{
templates = null;
}
}
@Override
public ListFacade<? extends TreeView<TemplateFacade>> getTreeViews()
{
return treeViews;
}
@Override
public int getDefaultTreeViewIndex()
{
return 0;
}
@Override
public DataView<TemplateFacade> getDataView()
{
return dataView;
}
@Override
public ListFacade<TemplateFacade> getDataModel()
{
if (isAvailModel)
{
return templates;
}
else
{
return character.getTemplates();
}
}
@Override
public void elementAdded(ListEvent<TemplateFacade> e)
{
templates.refilter();
}
@Override
public void elementRemoved(ListEvent<TemplateFacade> e)
{
templates.refilter();
}
@Override
public void elementsChanged(ListEvent<TemplateFacade> e)
{
templates.refilter();
}
@Override
public void elementModified(ListEvent<TemplateFacade> e)
{
templates.refilter();
}
@Override
public boolean accept(CharacterFacade context, TemplateFacade element)
{
return !context.getTemplates().containsElement(element);
}
}
private enum TemplateTreeView implements TreeView<TemplateFacade>
{
NAME("in_nameLabel"), //$NON-NLS-1$
TYPE_NAME("in_typeName"), //$NON-NLS-1$
SOURCE_NAME("in_sourceName"); //$NON-NLS-1$
private final String name;
private TemplateTreeView(String name)
{
this.name = LanguageBundle.getString(name);
}
@Override
public String getViewName()
{
return name;
}
@Override
public List<TreeViewPath<TemplateFacade>> getPaths(TemplateFacade pobj)
{
switch (this)
{
case NAME:
return Collections.singletonList(new TreeViewPath<>(pobj));
case TYPE_NAME:
return Collections.singletonList(new TreeViewPath<>(pobj,
pobj.getType()));
case SOURCE_NAME:
return Collections.singletonList(new TreeViewPath<>(pobj,
pobj.getSourceForNodeDisplay()));
default:
throw new InternalError();
}
}
}
}