📄 titledtab.java
字号:
/*
* Copyright (C) 2004 NNL Technology AB
* Visit www.infonode.net for information about InfoNode(R)
* products and how to contact NNL Technology AB.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
// $Id: TitledTab.java,v 1.88 2007/01/28 21:25:49 jesper Exp $
package net.infonode.tabbedpanel.titledtab;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.PanelUI;
import net.infonode.gui.DimensionProvider;
import net.infonode.gui.InsetsUtil;
import net.infonode.gui.RotatableLabel;
import net.infonode.gui.TranslatingShape;
import net.infonode.gui.border.FocusBorder;
import net.infonode.gui.hover.HoverEvent;
import net.infonode.gui.hover.HoverListener;
import net.infonode.gui.hover.hoverable.HoverManager;
import net.infonode.gui.hover.hoverable.Hoverable;
import net.infonode.gui.icon.IconProvider;
import net.infonode.gui.layout.StackableLayout;
import net.infonode.gui.panel.SimplePanel;
import net.infonode.gui.shaped.panel.ShapedPanel;
import net.infonode.properties.base.Property;
import net.infonode.properties.gui.InternalPropertiesUtil;
import net.infonode.properties.gui.util.ComponentProperties;
import net.infonode.properties.gui.util.ShapedPanelProperties;
import net.infonode.properties.propertymap.PropertyMapTreeListener;
import net.infonode.properties.propertymap.PropertyMapWeakListenerManager;
import net.infonode.properties.util.PropertyChangeListener;
import net.infonode.tabbedpanel.Tab;
import net.infonode.tabbedpanel.TabAdapter;
import net.infonode.tabbedpanel.TabEvent;
import net.infonode.tabbedpanel.TabRemovedEvent;
import net.infonode.tabbedpanel.TabSelectTrigger;
import net.infonode.tabbedpanel.TabbedPanel;
import net.infonode.tabbedpanel.TabbedPanelProperties;
import net.infonode.tabbedpanel.TabbedUtils;
import net.infonode.util.Alignment;
import net.infonode.util.Direction;
import net.infonode.util.ValueChange;
/**
* <p>A TitledTab is a tab that has support for text, icon and a custom Swing component
* (called title component). Titled tab supports several properties that makes it possible
* to change the look (borders, colors, insets), layout (up, down, left, right).</p>
*
* <p>Titled tab has a line based layout, i.e. the text, icon and title component are
* laid out in a line. The layout of the tab can be rotated, i.e. the text and the icon will
* be rotated 90, 180 or 270 degrees. The title component will not be rotated but moved so
* that the line layout will persist.</p>
*
* <p>A titled tab has 3 rendering states:
* <ul>
* <li>Normal - The tab is selectable but not yet selected
* <li>Highlighted - The tab is either highlighted or selected
* <li>Disabled - The tab is disabled and cannot be selected or highlighted
* </ul>Most of the properties for the tab can be configured for each of the tab rendering
* states.</p>
*
* <p><strong>Note:</strong> If only the normal state properties have been configured, the
* highlighted and disabled state will automatically use the same properties as for the normal
* state, see {@link TitledTabProperties} and {@link TitledTabStateProperties}.</p>
*
* <p>TitledTab implements the {@link net.infonode.gui.icon.IconProvider} interface and
* overloads toString() so that both text and icon for the normal state is shown in the
* tab drop down list in a tabbed panel.</p>
*
* <p>TitledTab supports mouse hovering. A {@link HoverListener} can be set in the
* {@link TitledTabProperties}. The hover listener receives a {@link HoverEvent} when the mouse
* enters or exits the tab. The hover event's source will be the affected titled tab.</p>
*
* @author $Author: jesper $
* @version $Revision: 1.88 $
* @see TitledTabProperties
* @see TitledTabStateProperties
*/
public class TitledTab extends Tab implements IconProvider {
private static PanelUI UI = new PanelUI() {
};
private class StatePanel extends SimplePanel {
private ShapedPanel panel = new ShapedPanel();
private SimplePanel titleComponentPanel = new SimplePanel();
private RotatableLabel label = new RotatableLabel(null, null) {
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
String text = this.getText();
Icon tmpIcon = this.getIcon();
if (text == null || tmpIcon == null) {
this.setText(" ");
this.setIcon(icon);
if (getDirection().isHorizontal())
d = new Dimension(d.width, super.getPreferredSize().height);
else
d = new Dimension(super.getPreferredSize().width, d.height);
this.setText(text);
this.setIcon(tmpIcon);
}
return d;
}
};
private JComponent titleComponent;
private Direction currentLayoutDirection;
private int currentLayoutGap = -1;
private Alignment currentLayoutAlignment;
private String toolTipText;
private Icon icon;
public StatePanel(Border focusBorder) {
super(new BorderLayout());
label.setBorder(focusBorder);
label.setMinimumSize(new Dimension(0, 0));
panel.add(label, BorderLayout.CENTER);
add(panel, BorderLayout.CENTER);
}
public String getToolTipText() {
return toolTipText;
}
public JComponent getTitleComponent() {
return titleComponent;
}
public Shape getShape() {
return panel.getShape();
}
public JLabel getLabel() {
return label;
}
public void setTitleComponent(JComponent titleComponent, TitledTabStateProperties stateProps) {
JComponent oldTitleComponent = this.titleComponent;
this.titleComponent = null;
if (oldTitleComponent != null && oldTitleComponent.getParent() == titleComponentPanel)
titleComponentPanel.remove(oldTitleComponent);
this.titleComponent = titleComponent;
updateLayout(stateProps, true);
}
public void activateTitleComponent() {
if (titleComponent != null) {
if (titleComponent.getParent() != titleComponentPanel) {
if (titleComponent.getParent() != null)
titleComponent.getParent().remove(titleComponent);
titleComponentPanel.add(titleComponent, BorderLayout.CENTER);
}
}
else {
titleComponentPanel.removeAll();
}
}
public void activate() {
remove(panel);
eventPanel.add(panel, BorderLayout.CENTER);
add(eventPanel, BorderLayout.CENTER);
}
public void deactivate() {
remove(eventPanel);
eventPanel.remove(panel);
add(panel, BorderLayout.CENTER);
}
public Dimension getPreferredSize() {
activateTitleComponent();
return getAdjustedSize(super.getPreferredSize());
}
public Dimension getMinimumSize() {
activateTitleComponent();
return getAdjustedSize(super.getMinimumSize());
}
public Dimension getMaximumSize() {
activateTitleComponent();
return super.getMaximumSize();
}
private Dimension getAdjustedSize(Dimension d) {
DimensionProvider prov = properties.getMinimumSizeProvider();
if (prov == null)
return d;
Dimension min = properties.getMinimumSizeProvider().getDimension(this);
if (min == null)
return d;
return new Dimension(Math.max(min.width, d.width), Math.max(min.height, d.height));
}
public JComponent getFocusableComponent() {
return label;
}
private void updateLayout(TitledTabStateProperties stateProperties, boolean titleComponentChanged) {
if (titleComponent != null && stateProperties.getTitleComponentVisible()) {
Direction d = stateProperties.getDirection();
int gap;
if (stateProperties.getIconVisible() || stateProperties.getTextVisible())
gap = stateProperties.getTextTitleComponentGap();
else
gap = 0;
Alignment alignment = stateProperties.getTitleComponentTextRelativeAlignment();
if (titleComponentPanel.getComponentCount() == 0 ||
(titleComponentPanel.getComponentCount() > 0 && titleComponentPanel.getComponent(0) != titleComponent) ||
titleComponentChanged ||
gap != currentLayoutGap ||
alignment != currentLayoutAlignment ||
d != currentLayoutDirection) {
titleComponentChanged = false;
currentLayoutDirection = d;
currentLayoutGap = gap;
currentLayoutAlignment = alignment;
panel.remove(titleComponentPanel);
if (d == Direction.UP) {
panel.add(titleComponentPanel, alignment == Alignment.LEFT ? BorderLayout.SOUTH : BorderLayout.NORTH);
titleComponentPanel.setBorder(
new EmptyBorder(alignment == Alignment.LEFT ? gap : 0, 0, alignment == Alignment.LEFT ? 0 : gap, 0));
}
else if (d == Direction.LEFT) {
panel.add(titleComponentPanel, alignment == Alignment.LEFT ? BorderLayout.EAST : BorderLayout.WEST);
titleComponentPanel.setBorder(
new EmptyBorder(0, alignment == Alignment.LEFT ? gap : 0, 0, alignment == Alignment.LEFT ? 0 : gap));
}
else if (d == Direction.DOWN) {
panel.add(titleComponentPanel, alignment == Alignment.LEFT ? BorderLayout.NORTH : BorderLayout.SOUTH);
titleComponentPanel.setBorder(
new EmptyBorder(alignment == Alignment.LEFT ? 0 : gap, 0, alignment == Alignment.LEFT ? gap : 0, 0));
}
else {
panel.add(titleComponentPanel, alignment == Alignment.LEFT ? BorderLayout.WEST : BorderLayout.EAST);
titleComponentPanel.setBorder(
new EmptyBorder(0, alignment == Alignment.LEFT ? 0 : gap, 0, alignment == Alignment.LEFT ? gap : 0));
}
panel.revalidate();
}
}
else {
panel.remove(titleComponentPanel);
titleComponentPanel.removeAll();
panel.revalidate();
}
}
public void updateShapedPanel(TitledTabStateProperties stateProperties) {
Direction tabAreaOrientation = getTabAreaOrientation();
ShapedPanelProperties shapedPanelProperties = stateProperties.getShapedPanelProperties();
InternalPropertiesUtil.applyTo(shapedPanelProperties, panel, tabAreaOrientation.getNextCW());
panel
.setHorizontalFlip(tabAreaOrientation == Direction.DOWN || tabAreaOrientation == Direction.LEFT ? !shapedPanelProperties
.getHorizontalFlip()
: shapedPanelProperties.getHorizontalFlip());
}
public void setBorders(Border outerBorder, Border innerBorder) {
setBorder(outerBorder);
panel.setBorder(innerBorder);
}
public boolean updateState(Map changes, TitledTabStateProperties stateProperties) {
boolean updateBorders = false;
if (changes == null) {
label.setText(stateProperties.getTextVisible() ? stateProperties.getText() : null);
icon = stateProperties.getIcon();
label.setIcon(stateProperties.getIconVisible() ? stateProperties.getIcon() : null);
label.setIconTextGap(stateProperties.getIconTextGap());
label.setDirection(stateProperties.getDirection());
Alignment alignment = stateProperties.getIconTextRelativeAlignment();
label.setHorizontalTextPosition(alignment == Alignment.LEFT ? JLabel.RIGHT :
JLabel.LEFT);
alignment = stateProperties.getHorizontalAlignment();
label.setHorizontalAlignment(alignment == Alignment.LEFT ? JLabel.LEFT :
alignment == Alignment.CENTER ? JLabel.CENTER :
JLabel.RIGHT);
alignment = stateProperties.getVerticalAlignment();
label.setVerticalAlignment(alignment == Alignment.TOP ? JLabel.TOP :
alignment == Alignment.CENTER ? JLabel.CENTER :
JLabel.BOTTOM);
toolTipText = stateProperties.getToolTipEnabled() ? stateProperties.getToolTipText() : null;
if (toolTipText != null && toolTipText.length() == 0)
toolTipText = null;
if (currentStatePanel == this)
eventPanel.setToolTipText(toolTipText);
updateLayout(stateProperties, true);
ComponentProperties componentProperties = stateProperties.getComponentProperties();
label.setFont(componentProperties.getFont());
Color c = componentProperties.getForegroundColor();
label.setForeground(c);
setForeground(c);
updateShapedPanel(stateProperties);
updateBorders = true;
}
else {
Map m = (Map) changes.get(stateProperties.getMap());
if (m != null) {
Set keySet = m.keySet();
if (keySet.contains(TitledTabStateProperties.TEXT) || keySet.contains(TitledTabStateProperties.TEXT_VISIBLE)) {
label.setText(stateProperties.getTextVisible() ? stateProperties.getText() : null);
}
if (keySet.contains(TitledTabStateProperties.ICON) || keySet.contains(TitledTabStateProperties.ICON_VISIBLE)) {
icon = stateProperties.getIcon();
label.setIcon(stateProperties.getIconVisible() ? stateProperties.getIcon() : null);
}
if (keySet.contains(TitledTabStateProperties.ICON_TEXT_GAP)) {
label.setIconTextGap(
((Integer) ((ValueChange) m.get(TitledTabStateProperties.ICON_TEXT_GAP)).getNewValue()).intValue());
}
if (keySet.contains(TitledTabStateProperties.ICON_TEXT_RELATIVE_ALIGNMENT)) {
Alignment alignment = (Alignment) ((ValueChange) m.get(
TitledTabStateProperties.ICON_TEXT_RELATIVE_ALIGNMENT)).getNewValue();
label.setHorizontalTextPosition(alignment == Alignment.LEFT ? JLabel.RIGHT : JLabel.LEFT);
}
if (keySet.contains(TitledTabStateProperties.HORIZONTAL_ALIGNMENT)) {
Alignment alignment = (Alignment) ((ValueChange) m.get(TitledTabStateProperties.HORIZONTAL_ALIGNMENT)).getNewValue();
label.setHorizontalAlignment(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -