/** * 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; } } }