package org.multibit.viewsystem.swing;
import org.multibit.controller.Controller;
import org.multibit.utils.ImageLoader;
import org.multibit.viewsystem.DisplayHint;
import org.multibit.viewsystem.Viewable;
import org.multibit.viewsystem.swing.view.components.FontSizer;
import org.multibit.viewsystem.swing.view.panels.HelpContentsPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.plaf.TabbedPaneUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
public class MultiBitTabbedPane extends JTabbedPane {
private static final long serialVersionUID = 6530125716859367873L;
private ImageIcon closeTabIcon;
private Dimension closeButtonSize;
private static final int CLOSE_ICON_WIDTH = 10;
private static final int CLOSE_ICON_HEIGHT = 10;
private static final int SEPARATION_DISTANCE = 2;
private int tabCounter = 0;
private Controller controller;
private final MultiBitTabbedPane thisTabbedPane;
private static boolean enableUpdates = false;
private static final Logger log = LoggerFactory.getLogger(MultiBitTabbedPane.class);
public MultiBitTabbedPane(final Controller controller) {
thisTabbedPane = this;
this.controller = controller;
applyComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()));
// Create an image icon of the small 'X' for use with a close
// button on each tab. The png loaded is a 10x10 graphic
closeTabIcon = ImageLoader.createImageIcon(ImageLoader.CLOSE_TAB_ICON_FILE);
// Create a Dimension that can be used to size the close buttons.
closeButtonSize = new Dimension(CLOSE_ICON_WIDTH + SEPARATION_DISTANCE, CLOSE_ICON_HEIGHT + SEPARATION_DISTANCE);
ToolTipManager.sharedInstance().registerComponent(this);
}
@Override
public void setSelectedIndex(int index) {
super.setSelectedIndex(index);
if (!enableUpdates) {
return;
}
log.debug("Set selected index = " + index);
try {
// Get current tab.
JPanel tabPanelComponent = (JPanel) getComponentAt(index);
Viewable selectedView = null;
if (tabPanelComponent != null) {
Component[] childComponents = tabPanelComponent.getComponents();
selectedView = null;
if (childComponents != null && childComponents.length > 0 && childComponents[0] instanceof Viewable) {
selectedView = ((Viewable) childComponents[0]);
if (selectedView != null && controller.getCurrentView() == selectedView.getViewId()) {
// We are already displaying the correct tab.
// Just update the contents.
selectedView.displayView(DisplayHint.COMPLETE_REDRAW);
controller.fireDataChangedUpdateNow();
} else {
// Select the new tab, update the content.
controller.setCurrentView(selectedView.getViewId());
selectedView.displayView(DisplayHint.COMPLETE_REDRAW);
// Fire data change but no need to redisplay the view
enableUpdates = false;
controller.fireDataChangedUpdateNow();
enableUpdates = true;
}
}
}
Component tabComponent = getTabComponentAt(index);
if (tabComponent != null && tabComponent instanceof JLabel) {
JLabel tabLabel = (JLabel) tabComponent;
if (selectedView != null) {
tabLabel.setToolTipText(HelpContentsPanel.createTooltipText(selectedView.getViewTooltip()));
}
}
} catch (Throwable e) {
// Do not let errors percolate out of tab display.
log.error(e.getClass().getName() + " " + e.getMessage());
}
}
public Viewable getCurrentlyShownView() {
// Get current tab.
JPanel tabComponent = (JPanel) getSelectedComponent();
if (tabComponent != null) {
Component[] childComponents = tabComponent.getComponents();
Viewable selectedView = null;
if (childComponents != null && childComponents.length > 0 && childComponents[0] instanceof Viewable) {
selectedView = ((Viewable) childComponents[0]);
return selectedView;
}
}
return null;
}
@Override
public void addTab(String title, Icon icon, Component component) {
addTab(title, icon, "", component, false);
}
public void addTab(String title, Icon icon, String tooltip, Component component) {
addTab(title, icon, tooltip, component, false);
}
public void addTab(String title, Icon icon, String tooltip, Component component, boolean isCloseable) {
final Component finalComponent = component;
// Create a panel that represents the tab and ensure that it is
// transparent.
JPanel tab = new JPanel(new GridBagLayout());
tab.applyComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()));
GridBagConstraints constraints = new GridBagConstraints();
tab.setOpaque(false);
// Create a label and a Close button for the tab. Be sure to
// set its preferred size to nearly the size of the icon, and
// create an action listener that will locate the tab and
// remote it from the tabbed pane.
JLabel tabLabel = new JLabel(title);
tabLabel.setFont(FontSizer.INSTANCE.getAdjustedDefaultFont());
tabLabel.setIcon(icon);
tabLabel.applyComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()));
tabCounter++;
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0.8;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.CENTER;
tab.add(tabLabel, constraints);
if (isCloseable) {
JButton tabCloseButton = new JButton(closeTabIcon);
tabCloseButton.setPreferredSize(closeButtonSize);
tabCloseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int closeTabNumber = thisTabbedPane.indexOfComponent(finalComponent);
thisTabbedPane.removeTabAt(closeTabNumber);
// notify controller of new view being shown
JPanel selectedTab = (JPanel) thisTabbedPane.getSelectedComponent();
Component[] components = selectedTab.getComponents();
if (components != null && components.length > 0 && components[0] instanceof Viewable) {
Viewable selectedView = (Viewable) components[0];
selectedView.displayView(DisplayHint.COMPLETE_REDRAW);
controller.displayView(selectedView.getViewId());
}
}
});
JPanel fill1 = new JPanel();
fill1.setOpaque(false);
fill1.setMinimumSize(new Dimension(4, 4));
fill1.setPreferredSize(new Dimension(4, 4));
fill1.setMaximumSize(new Dimension(4, 4));
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 1;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0.05;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.CENTER;
tab.add(fill1, constraints);
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 2;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0.2;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.BASELINE_TRAILING;
tab.add(tabCloseButton, constraints);
}
// Add the tab to the tabbed pane. Note that the first
// parameter, which would ordinarily be a String that
// represents the tab title, is null.
addTab(null, component);
// Instead of using a String/Icon combination for the tab,
// use our panel instead.
ToolTipManager.sharedInstance().unregisterComponent(tab);
setTabComponentAt(getTabCount() - 1, tab);
}
@Override
public String getToolTipText(MouseEvent e) {
int index = ((TabbedPaneUI)ui).tabForCoordinate(this, e.getX(), e.getY());
if (index != -1) {
JComponent selectedTab = (JComponent)getComponentAt(index);
Component[] components = selectedTab.getComponents();
if (components != null && components.length > 0 && components[0] instanceof Viewable) {
return HelpContentsPanel.createTooltipText(((Viewable) components[0]).getViewTooltip());
}
}
return null;
}
public void removeAllTabs() {
int tabCount = this.getTabCount();
for (int i = 0; i < tabCount; i++) {
this.removeTabAt(0);
}
}
public static boolean isEnableUpdates() {
return enableUpdates;
}
public static void setEnableUpdates(boolean enableUpdates) {
MultiBitTabbedPane.enableUpdates = enableUpdates;
}
public Insets getInsets() {
return new Insets(0, 0, 0, 0);
}
}