/*
* CharacterTabs.java
* Copyright 2009 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 Aug 29, 2009, 2:59:53 PM
*/
package pcgen.gui2;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.commons.lang3.StringUtils;
import pcgen.facade.core.CharacterFacade;
import pcgen.facade.util.ReferenceFacade;
import pcgen.facade.util.event.ListEvent;
import pcgen.facade.util.event.ListListener;
import pcgen.facade.util.event.ReferenceEvent;
import pcgen.facade.util.event.ReferenceListener;
import pcgen.facade.util.ListFacade;
import pcgen.gui2.tabs.InfoTabbedPane;
import pcgen.gui2.tools.Icons;
import pcgen.gui2.util.SharedTabPane;
import pcgen.system.CharacterManager;
/**
* This is the tabbed pane for PCGen characters. Unlike normal tabbed panes, the
* CharacterTabs pane really only has a component single child component, the
* InfoTabbedPane. The CharacterTabs pane is responsible for notifying both the
* PCGenFrame and the InfoTabbedPane when a change in character selection
* occurs.
*
* @see pcgen.gui2.PCGenFrame
* @see pcgen.gui2.tabs.InfoTabbedPane
* @author Connor Petty <cpmeister@users.sourceforge.net>
*/
public final class CharacterTabs extends SharedTabPane
implements ChangeListener, ReferenceListener<CharacterFacade>, ListListener<CharacterFacade>
{
private final PCGenFrame frame;
//This holds the list of characters as well as the order in which they are displayed
private final List<CharacterFacade> characters;
private final Map<CharacterFacade, TabLabel> listenerMap;
private final InfoTabbedPane infoTabbedPane;
private final JPopupMenu popupMenu;
public CharacterTabs(PCGenFrame frame)
{
this.frame = frame;
this.characters = new ArrayList<>();
this.infoTabbedPane = new InfoTabbedPane();
this.listenerMap = new HashMap<>();
this.popupMenu = new JPopupMenu();
initComponents();
}
private void initComponents()
{
CharacterManager.getCharacters().addListListener(this);
frame.getSelectedCharacterRef().addReferenceListener(this);
setTabPlacement(SwingConstants.BOTTOM);
addChangeListener(this);
setSharedComponent(infoTabbedPane);
//Initialize popup menu
PCGenActionMap actions = frame.getActionMap();
popupMenu.add(actions.get(PCGenActionMap.NEW_COMMAND));
popupMenu.add(actions.get(PCGenActionMap.CLOSE_COMMAND));
popupMenu.add(actions.get(PCGenActionMap.SAVE_COMMAND));
popupMenu.add(actions.get(PCGenActionMap.SAVEAS_COMMAND));
addMouseListener(new PopupListener());
}
private void addCharacter(CharacterFacade character)
{
characters.add(character);
TabLabel tabLabel = new TabLabel(character);
addTab(tabLabel);
listenerMap.put(character, tabLabel);
}
private void removeCharacter(CharacterFacade character)
{
int index = characters.indexOf(character);
characters.remove(index);
removeTabAt(index);
listenerMap.remove(character).removeListeners();
infoTabbedPane.characterRemoved(character);
}
@Override
public void referenceChanged(ReferenceEvent<CharacterFacade> e)
{
setSelectedIndex(characters.indexOf(e.getNewReference()));
}
@Override
public void stateChanged(ChangeEvent e)
{
int index = getSelectedIndex();
CharacterFacade character = index != -1 ? characters.get(index) : null;
frame.setSelectedCharacter(character);
if (character != null)
{
infoTabbedPane.setCharacter(character);
}
else
{
infoTabbedPane.clearStateMap();
}
}
@Override
public void elementAdded(ListEvent<CharacterFacade> e)
{
addCharacter(e.getElement());
}
@Override
public void elementRemoved(ListEvent<CharacterFacade> e)
{
removeCharacter(e.getElement());
}
@Override
public void elementsChanged(ListEvent<CharacterFacade> e)
{
removeAll();
for (CharacterFacade character : characters)
{
listenerMap.remove(character).removeListeners();
}
characters.clear();
for (CharacterFacade character : (ListFacade<CharacterFacade>) e.getSource())
{
addCharacter(character);
}
infoTabbedPane.clearStateMap();
}
@Override
public void elementModified(ListEvent<CharacterFacade> e)
{
}
private class TabLabel extends JPanel implements ActionListener, ReferenceListener<String>
{
private JLabel titleLabel;
private JButton closeButton;
private CharacterFacade character;
private ReferenceFacade<String> tabNameRef;
private ReferenceFacade<String> nameRef;
public TabLabel(CharacterFacade character)
{
super(new FlowLayout(FlowLayout.CENTER, 5, 2));
this.character = character;
this.tabNameRef = character.getTabNameRef();
this.nameRef = character.getNameRef();
initComponents();
closeButton.addActionListener(this);
tabNameRef.addReferenceListener(this);
nameRef.addReferenceListener(this);
}
private void initComponents()
{
if (StringUtils.isNotEmpty(tabNameRef.get()))
{
titleLabel = new JLabel(tabNameRef.get());
}
else
{
titleLabel = new JLabel(nameRef.get());
}
add(titleLabel);
closeButton = new JButton();
closeButton.setMargin(new Insets(0, 0, 0, 0));
closeButton.setBorder(BorderFactory.createEmptyBorder());
closeButton.setFocusable(false);
closeButton.setBorderPainted(false);
closeButton.setContentAreaFilled(false);
closeButton.setRolloverEnabled(true);
ImageIcon icon = Icons.XButton_Stat.getImageIcon();
Dimension size = new Dimension(icon.getIconWidth(), icon.getIconHeight());
Insets insets = closeButton.getInsets();
size.width += insets.left + insets.right;
size.height += insets.top + insets.bottom;
closeButton.setMinimumSize(size);
closeButton.setPreferredSize(size);
closeButton.setMaximumSize(size);
closeButton.setIcon(icon);
closeButton.setRolloverIcon(Icons.XButton_Roll.getImageIcon());
closeButton.setPressedIcon(Icons.XButton_Click.getImageIcon());
add(closeButton);
setOpaque(false);
}
public void removeListeners()
{
tabNameRef.removeReferenceListener(this);
nameRef.removeReferenceListener(this);
}
@Override
public void referenceChanged(ReferenceEvent<String> e)
{
if (e.getSource() == nameRef)
{
if (StringUtils.isEmpty(tabNameRef.get()))
{
titleLabel.setText(e.getNewReference());
}
}
else
{
if (StringUtils.isNotEmpty(e.getNewReference()))
{
titleLabel.setText(e.getNewReference());
}
else
{
titleLabel.setText(nameRef.get());
}
}
}
@Override
public void actionPerformed(ActionEvent e)
{
frame.closeCharacter(character);
}
}
private class PopupListener extends MouseAdapter
{
@Override
public void mousePressed(MouseEvent e)
{
maybeShowPopup(e);
}
@Override
public void mouseReleased(MouseEvent e)
{
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e)
{
if (e.isPopupTrigger())
{
popupMenu.setVisible(true);
popupMenu.show(e.getComponent(),
e.getX(), e.getY() - popupMenu.getHeight());
}
}
}
}