/**
* L2FProd.com Common Components 7.3 License.
*
* Copyright 2005-2007 L2FProd.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.l2fprod.common.swing.plaf.basic;
import com.l2fprod.common.swing.JCollapsiblePane;
import com.l2fprod.common.swing.JLinkButton;
import com.l2fprod.common.swing.JTaskPaneGroup;
import com.l2fprod.common.swing.icons.EmptyIcon;
import com.l2fprod.common.swing.plaf.TaskPaneGroupUI;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicGraphicsUtils;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* Base implementation of the <code>JTaskPaneGroup</code> UI.
*/
public class BasicTaskPaneGroupUI extends TaskPaneGroupUI {
private static FocusListener focusListener = new RepaintOnFocus();
public static ComponentUI createUI(JComponent c) {
return new BasicTaskPaneGroupUI();
}
protected static int TITLE_HEIGHT = 25;
protected static int ROUND_HEIGHT = 5;
protected JTaskPaneGroup group;
protected boolean mouseOver;
protected MouseInputListener mouseListener;
protected PropertyChangeListener propertyListener;
public void installUI(JComponent c) {
super.installUI(c);
group = (JTaskPaneGroup) c;
installDefaults();
installListeners();
installKeyboardActions();
}
protected void installDefaults() {
group.setOpaque(true);
group.setBorder(createPaneBorder());
((JComponent) group.getContentPane()).setBorder(createContentPaneBorder());
LookAndFeel.installColorsAndFont(group, "TaskPaneGroup.background", "TaskPaneGroup.foreground", "TaskPaneGroup.font");
LookAndFeel.installColorsAndFont((JComponent) group.getContentPane(), "TaskPaneGroup.background", "TaskPaneGroup.foreground",
"TaskPaneGroup.font");
}
protected void installListeners() {
mouseListener = createMouseInputListener();
group.addMouseMotionListener(mouseListener);
group.addMouseListener(mouseListener);
group.addFocusListener(focusListener);
propertyListener = createPropertyListener();
group.addPropertyChangeListener(propertyListener);
}
protected void installKeyboardActions() {
InputMap inputMap = (InputMap) UIManager.get("TaskPaneGroup.focusInputMap");
if (inputMap != null) {
SwingUtilities.replaceUIInputMap(group, JComponent.WHEN_FOCUSED, inputMap);
}
ActionMap map = getActionMap();
if (map != null) {
SwingUtilities.replaceUIActionMap(group, map);
}
}
ActionMap getActionMap() {
ActionMap map = new ActionMapUIResource();
map.put("toggleExpanded", new ToggleExpandedAction());
return map;
}
public void uninstallUI(JComponent c) {
uninstallListeners();
super.uninstallUI(c);
}
protected void uninstallListeners() {
group.removeMouseListener(mouseListener);
group.removeMouseMotionListener(mouseListener);
group.removeFocusListener(focusListener);
group.removePropertyChangeListener(propertyListener);
}
protected MouseInputListener createMouseInputListener() {
return new ToggleListener();
}
protected PropertyChangeListener createPropertyListener() {
return new ChangeListener();
}
protected boolean isInBorder(MouseEvent event) {
return event.getY() < getTitleHeight();
}
protected final int getTitleHeight() {
return TITLE_HEIGHT;
}
protected Border createPaneBorder() {
return new PaneBorder();
}
public Dimension getPreferredSize(JComponent c) {
Component component = group.getComponent(0);
if (!(component instanceof JCollapsiblePane)) {
// something wrong in this JTaskPaneGroup
return super.getPreferredSize(c);
}
JCollapsiblePane collapsible = (JCollapsiblePane) component;
Dimension dim = collapsible.getPreferredSize();
Border groupBorder = group.getBorder();
if (groupBorder instanceof PaneBorder) {
Dimension border = ((PaneBorder) groupBorder).getPreferredSize(group);
dim.width = Math.max(dim.width, border.width);
dim.height += border.height;
} else {
dim.height += getTitleHeight();
}
return dim;
}
protected Border createContentPaneBorder() {
Color borderColor = UIManager.getColor("TaskPaneGroup.borderColor");
return new CompoundBorder(new ContentPaneBorder(borderColor), BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
public Component createAction(Action action) {
JLinkButton link = new JLinkButton(action) {
public void updateUI() {
super.updateUI();
// ensure the ui of this link is correctly update on l&f changes
if (BasicTaskPaneGroupUI.this != null)
configure(this);
}
};
configure(link);
return link;
}
protected void configure(JLinkButton link) {
link.setOpaque(false);
link.setBorder(null);
link.setBorderPainted(false);
link.setFocusPainted(true);
link.setForeground(UIManager.getColor("TaskPaneGroup.titleForeground"));
}
protected void ensureVisible() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
group.scrollRectToVisible(new Rectangle(group.getWidth(), group.getHeight()));
}
});
}
static class RepaintOnFocus implements FocusListener {
public void focusGained(FocusEvent e) {
e.getComponent().repaint();
}
public void focusLost(FocusEvent e) {
e.getComponent().repaint();
}
}
class ChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
// if group is expanded but not animated
// or if animated has reached expanded state
// scroll to visible if scrollOnExpand is enabled
if ((JTaskPaneGroup.EXPANDED_CHANGED_KEY.equals(evt.getPropertyName()) && Boolean.TRUE.equals(evt.getNewValue()) &&
!group.isAnimated()) ||
(JCollapsiblePane.ANIMATION_STATE_KEY.equals(evt.getPropertyName()) && "expanded".equals(evt.getNewValue()))) {
if (group.isScrollOnExpand()) {
ensureVisible();
}
} else if (JTaskPaneGroup.ICON_CHANGED_KEY.equals(evt.getPropertyName()) ||
JTaskPaneGroup.TITLE_CHANGED_KEY.equals(evt.getPropertyName()) ||
JTaskPaneGroup.SPECIAL_CHANGED_KEY.equals(evt.getPropertyName()) ||
JTaskPaneGroup.COLLAPSABLE_CHANGED_KEY.equals(evt.getPropertyName())) {
// icon, title, special must lead to a repaint()
group.repaint();
}
}
}
class ToggleListener extends MouseInputAdapter {
public void mouseEntered(MouseEvent e) {
if (isInBorder(e)) {
e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
mouseOver = false;
group.repaint();
}
}
public void mouseExited(MouseEvent e) {
e.getComponent().setCursor(null);
mouseOver = false;
group.repaint();
}
public void mouseMoved(MouseEvent e) {
if (isInBorder(e) && group.isCollapsable()) {
e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
mouseOver = true;
group.repaint();
} else {
e.getComponent().setCursor(null);
mouseOver = false;
group.repaint();
}
}
public void mouseReleased(MouseEvent e) {
if (isInBorder(e) && group.isCollapsable()) {
group.setExpanded(!group.isExpanded());
}
}
}
class ToggleExpandedAction extends AbstractAction {
public ToggleExpandedAction() {
super("toggleExpanded");
}
public void actionPerformed(ActionEvent e) {
group.setExpanded(!group.isExpanded());
}
public boolean isEnabled() {
return group.isVisible() && group.isCollapsable();
}
}
protected static class ChevronIcon implements Icon {
boolean up = true;
public ChevronIcon(boolean up) {
this.up = up;
}
public int getIconHeight() {
return 3;
}
public int getIconWidth() {
return 6;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
if (up) {
g.drawLine(x + 3, y, x, y + 3);
g.drawLine(x + 3, y, x + 6, y + 3);
} else {
g.drawLine(x, y, x + 3, y + 3);
g.drawLine(x + 3, y + 3, x + 6, y);
}
}
}
/**
* The border around the content pane
*/
protected static class ContentPaneBorder implements Border {
Color color;
public ContentPaneBorder(Color color) {
this.color = color;
}
public Insets getBorderInsets(Component c) {
return new Insets(0, 1, 1, 1);
}
public boolean isBorderOpaque() {
return true;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.setColor(color);
g.drawLine(x, y, x, y + height - 1);
g.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
g.drawLine(x + width - 1, y, x + width - 1, y + height - 1);
}
}
/**
* The border of the taskpane group paints the "text", the "icon", the
* "expanded" status and the "special" type.
*/
protected class PaneBorder implements Border {
protected Color borderColor;
protected Color titleForeground;
protected Color specialTitleBackground;
protected Color specialTitleForeground;
protected Color titleBackgroundGradientStart;
protected Color titleBackgroundGradientEnd;
protected Color titleOver;
protected Color specialTitleOver;
protected JLabel label;
public PaneBorder() {
borderColor = UIManager.getColor("TaskPaneGroup.borderColor");
titleForeground = UIManager.getColor("TaskPaneGroup.titleForeground");
specialTitleBackground = UIManager.getColor("TaskPaneGroup.specialTitleBackground");
specialTitleForeground = UIManager.getColor("TaskPaneGroup.specialTitleForeground");
titleBackgroundGradientStart = UIManager.getColor("TaskPaneGroup.titleBackgroundGradientStart");
titleBackgroundGradientEnd = UIManager.getColor("TaskPaneGroup.titleBackgroundGradientEnd");
titleOver = UIManager.getColor("TaskPaneGroup.titleOver");
if (titleOver == null) {
titleOver = specialTitleBackground.brighter();
}
specialTitleOver = UIManager.getColor("TaskPaneGroup.specialTitleOver");
if (specialTitleOver == null) {
specialTitleOver = specialTitleBackground.brighter();
}
label = new JLabel();
label.setOpaque(false);
label.setIconTextGap(8);
}
public Insets getBorderInsets(Component c) {
return new Insets(getTitleHeight(), 0, 0, 0);
}
public boolean isBorderOpaque() {
return true;
}
/**
* Calculates the preferred border size, its size so all its content fits.
*/
public Dimension getPreferredSize(JTaskPaneGroup group) {
// calculate the title width so it is fully visible
// it starts with the title width
configureLabel(group);
Dimension dim = label.getPreferredSize();
// add the title left offset
dim.width += 3;
// add the controls width
dim.width += TITLE_HEIGHT;
// and some space between label and controls
dim.width += 3;
dim.height = getTitleHeight();
return dim;
}
protected void paintTitleBackground(JTaskPaneGroup group, Graphics g) {
if (group.isSpecial()) {
g.setColor(specialTitleBackground);
} else {
g.setColor(titleBackgroundGradientStart);
}
g.fillRect(0, 0, group.getWidth(), getTitleHeight() - 1);
}
protected void paintTitle(JTaskPaneGroup group, Graphics g, Color textColor, int x, int y, int width, int height) {
configureLabel(group);
label.setForeground(textColor);
g.translate(x, y);
label.setBounds(0, 0, width, height);
label.paint(g);
g.translate(-x, -y);
}
protected void configureLabel(JTaskPaneGroup group) {
label.applyComponentOrientation(group.getComponentOrientation());
label.setFont(group.getFont());
label.setText(group.getTitle());
label.setIcon(group.getIcon() == null ? new EmptyIcon() : group.getIcon());
}
protected void paintExpandedControls(JTaskPaneGroup group, Graphics g, int x, int y, int width, int height) {}
protected Color getPaintColor(JTaskPaneGroup group) {
Color paintColor;
if (isMouseOverBorder()) {
if (mouseOver) {
if (group.isSpecial()) {
paintColor = specialTitleOver;
} else {
paintColor = titleOver;
}
} else {
if (group.isSpecial()) {
paintColor = specialTitleForeground;
} else {
paintColor = titleForeground;
}
}
} else {
if (group.isSpecial()) {
paintColor = specialTitleForeground;
} else {
paintColor = titleForeground;
}
}
return paintColor;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
JTaskPaneGroup group = (JTaskPaneGroup) c;
// calculate position of title and toggle controls
int controlWidth = TITLE_HEIGHT - 2 * ROUND_HEIGHT;
// oval looks more like a circle with odd width
if (controlWidth % 2 != 0) { controlWidth++; }
int controlX = group.getWidth() - TITLE_HEIGHT;
int controlY = ROUND_HEIGHT - 1;
int titleX = 3;
int titleY = 0;
int titleWidth = group.getWidth() - getTitleHeight() - 3;
int titleHeight = getTitleHeight();
if (!group.getComponentOrientation().isLeftToRight()) {
controlX = group.getWidth() - controlX - controlWidth;
titleX = group.getWidth() - titleX - titleWidth;
}
// paint the title background
paintTitleBackground(group, g);
// paint the the toggles
if (group.isCollapsable()) {
paintExpandedControls(group, g, controlX, controlY, controlWidth, controlWidth);
}
// paint the title text and icon
Color paintColor = getPaintColor(group);
// focus painted same color as text
if (group.hasFocus()) {
paintFocus(g, paintColor, 3, 3, width - 6, getTitleHeight() - 6);
}
paintTitle(group, g, paintColor, titleX, titleY, titleWidth, titleHeight);
}
protected void paintRectAroundControls(JTaskPaneGroup group,
Graphics g,
int x,
int y,
int width,
int height,
Color highColor,
Color lowColor) {
if (mouseOver) {
int x2 = x + width;
int y2 = y + height;
g.setColor(highColor);
g.drawLine(x, y, x2, y);
g.drawLine(x, y, x, y2);
g.setColor(lowColor);
g.drawLine(x2, y, x2, y2);
g.drawLine(x, y2, x2, y2);
}
}
protected void paintOvalAroundControls(JTaskPaneGroup group, Graphics g, int x, int y, int width, int height) {
if (group.isSpecial()) {
g.setColor(specialTitleBackground.brighter());
g.drawOval(x, y, width, height);
} else {
g.setColor(titleBackgroundGradientStart);
g.fillOval(x, y, width, width);
g.setColor(titleBackgroundGradientEnd.darker());
g.drawOval(x, y, width, width);
}
}
protected void paintChevronControls(JTaskPaneGroup group, Graphics g, int x, int y, int width, int height) {
ChevronIcon chevron;
if (group.isExpanded()) {
chevron = new ChevronIcon(true);
} else {
chevron = new ChevronIcon(false);
}
int chevronX = x + width / 2 - chevron.getIconWidth() / 2;
int chevronY = y + (height / 2 - chevron.getIconHeight()) - (group.isExpanded() ? 1 : 0);
chevron.paintIcon(group, g, chevronX, chevronY);
chevron.paintIcon(group, g, chevronX, chevronY + chevron.getIconHeight() + 1);
}
protected void paintFocus(Graphics g, Color paintColor, int x, int y, int width, int height) {
g.setColor(paintColor);
BasicGraphicsUtils.drawDashedRect(g, x, y, width, height);
}
/**
* Default implementation returns false.
*
* @return true if this border wants to display things differently when the
* mouse is over it
*/
protected boolean isMouseOverBorder() {
return false;
}
}
}