![JAR search and dependency download from the Maven repository](/logo.png)
org.datacleaner.widgets.tabs.CloseableTabbedPane Maven / Gradle / Ivy
/**
* DataCleaner (community edition)
* Copyright (C) 2014 Free Software Foundation, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.datacleaner.widgets.tabs;
import java.awt.Color;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeListener;
import org.datacleaner.panels.DCBannerPanel;
import org.datacleaner.util.WidgetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a slightly rewritten/modified version of swingutil's
* ClosableTabbedPane
*/
public final class CloseableTabbedPane extends JTabbedPane {
public static final Color COLOR_BACKGROUND = WidgetUtils.COLOR_DEFAULT_BACKGROUND;
public static final Color COLOR_FOREGROUND_SELECTED = WidgetUtils.BG_COLOR_DARKEST;
public static final Color COLOR_FOREGROUND = WidgetUtils.BG_COLOR_LESS_DARK;
private static final long serialVersionUID = -411551524171347329L;
private static Logger _logger = LoggerFactory.getLogger(CloseableTabbedPane.class);
private final List _closeListeners = new LinkedList<>();
private final List _unclosables = new LinkedList<>();
private final List _separators = new LinkedList<>();
private final Map _doubleClickActionListeners = new HashMap<>();
private final Map _rightClickActionListeners = new HashMap<>();
/**
* Create a tabbed pane using defaults
*/
public CloseableTabbedPane() {
this(true);
}
/**
* Create a tabbed pane
*
* @param addBorder
* add a small border around the tabbed pane?
*/
public CloseableTabbedPane(final boolean addBorder) {
super(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);
setUI(new CloseableTabbedPaneUI(this));
setForeground(COLOR_FOREGROUND);
setBackground(COLOR_BACKGROUND);
setOpaque(true);
if (addBorder) {
setBorder(WidgetUtils.BORDER_WIDE_DEFAULT);
}
}
/**
* Tyically, the last tab open is not closable. So, call this method with a
* tab number and that tab will not contain a close icon. If you monitor
* with a {@link TabCloseListener}, you can use {@link #getTabCount()} and
* when it is 1, you can call {@link #setUncloseableTab(int)}(0) to make the
* last tab unclosable.
*
* @return the tabbed pane itself
*/
public CloseableTabbedPane setUnclosableTab(final int val) {
if (!_unclosables.contains(val)) {
_unclosables.add(val);
}
return this;
}
public void addSeparator() {
synchronized (this) {
final int tabCountBefore = getTabCount();
addTab("SEPARATOR", new JLabel());
_separators.add(tabCountBefore);
}
}
/**
* Use this method to reverse the actions of {@link #setUnclosableTab(int)}
*/
public void setClosableTab(final int val) {
// cast to Object to ensure the RIGHT remove(...) method is invoked in
// _unclosables
final Object value = Integer.valueOf(val);
_unclosables.remove(value);
}
@SuppressWarnings("unchecked")
public List getTabsOfClass(final Class clazz) {
final List list = new ArrayList<>();
final Component[] components = getComponents();
for (Component component : components) {
if (component instanceof JScrollPane) {
component = ((JScrollPane) component).getViewport().getComponent(0);
}
if (clazz.isAssignableFrom(component.getClass())) {
list.add((E) component);
}
}
return list;
}
/**
* Add a tab close listener. On close events, the listener is responsible
* for deleting the tab or otherwise reacting to the event.
*/
public void addTabCloseListener(final TabCloseListener lis) {
_closeListeners.add(lis);
}
/** Remove a tab close listener */
public void removeTabCloseListener(final TabCloseListener lis) {
_closeListeners.remove(lis);
}
public void closeTab(final int tabIndex) {
final Component component = getComponent(tabIndex);
remove(tabIndex);
int selectedIndex = getSelectedIndex();
while (_separators.contains(selectedIndex) && selectedIndex > 0) {
// make sure the separator tabs are not "selected"
selectedIndex = selectedIndex - 1;
setSelectedIndex(selectedIndex);
}
if (!_closeListeners.isEmpty()) {
final TabCloseEvent ev = new TabCloseEvent(this, tabIndex, component);
for (final TabCloseListener l : _closeListeners) {
try {
l.tabClosed(ev);
} catch (final Exception ex) {
_logger.error(ex.toString(), ex);
}
}
}
}
@Override
public void remove(final Component component) {
final int index = indexOfComponent(component);
remove(index);
}
@Override
public void remove(final int removedIndex) {
if (removedIndex < 0) {
return;
}
super.remove(removedIndex);
_rightClickActionListeners.remove(removedIndex);
_doubleClickActionListeners.remove(removedIndex);
// move all right click listeners for tabs above this index down
{
final Set keySet = new TreeSet<>(Collections.reverseOrder());
keySet.addAll(_rightClickActionListeners.keySet());
for (final Integer key : keySet) {
final int curIndex = key.intValue();
if (curIndex > removedIndex) {
final ActionListener actionListener = _rightClickActionListeners.get(curIndex);
_rightClickActionListeners.remove(curIndex);
_rightClickActionListeners.put(curIndex - 1, actionListener);
}
}
}
// move all double click listeners for tabs above this index down
{
final Set keySet = new TreeSet<>(Collections.reverseOrder());
keySet.addAll(_doubleClickActionListeners.keySet());
for (final Integer key : keySet) {
final int curIndex = key.intValue();
if (curIndex > removedIndex) {
final ActionListener actionListener = _doubleClickActionListeners.get(curIndex);
_doubleClickActionListeners.remove(curIndex);
_doubleClickActionListeners.put(curIndex - 1, actionListener);
}
}
}
// moved all the uncloseable tabs for tabs above this index down
{
for (final ListIterator it = _unclosables.listIterator(); it.hasNext(); ) {
final Integer tabIndex = it.next();
final int curIndex = tabIndex.intValue();
if (curIndex == removedIndex) {
it.remove();
} else if (curIndex > removedIndex) {
it.set(curIndex - 1);
}
}
}
}
@Override
public void setSelectedIndex(int index) {
if (getSeparators().contains(index)) {
index--;
setSelectedIndex(index);
} else {
super.setSelectedIndex(index);
}
}
public void closeAllTabs() {
for (int i = getTabCount() - 1; i >= 0; i--) {
closeTab(i);
}
removeAll();
}
protected List getUnclosables() {
return _unclosables;
}
protected List getSeparators() {
return _separators;
}
public void setRightClickActionListener(final int index, final ActionListener actionListener) {
_rightClickActionListeners.put(index, actionListener);
}
public ActionListener getRightClickActionListener(final int index) {
return _rightClickActionListeners.get(index);
}
public void setDoubleClickActionListener(final int index, final ActionListener actionListener) {
_doubleClickActionListeners.put(index, actionListener);
}
public ActionListener getDoubleClickActionListener(final int index) {
return _doubleClickActionListeners.get(index);
}
@Override
public Color getForegroundAt(final int index) {
if (getSelectedIndex() == index) {
return COLOR_FOREGROUND_SELECTED;
}
return super.getForegroundAt(index);
}
@Override
public void updateUI() {
repaint();
}
public boolean isCloseable(final int index) {
return !isUncloseable(index);
}
public boolean isUncloseable(final int index) {
return _unclosables.contains(index);
}
public Rectangle getTabBounds(final int tabIndex) {
return getUI().getTabBounds(this, tabIndex);
}
public void bindTabTitleToBanner(final DCBannerPanel bannerPanel) {
final ChangeListener changeListener = e -> {
final int selectedIndex = getSelectedIndex();
if (selectedIndex == -1) {
return;
}
final String title = getTitleAt(selectedIndex);
bannerPanel.setTitle2(title);
bannerPanel.updateUI();
};
addChangeListener(changeListener);
// trigger an initial update
changeListener.stateChanged(null);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy