/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tiny Look and Feel * * * * (C) Copyright 2003 - 2007 Hans Bickel * * * * For licensing information and credits, please refer to the * * comment in file de.muntjak.tinylookandfeel.TinyLookAndFeel * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package de.muntjak.tinylookandfeel; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Event; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.Action; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JInternalFrame; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicInternalFrameTitlePane; import javax.swing.plaf.metal.MetalInternalFrameTitlePane; import javax.swing.plaf.metal.MetalLookAndFeel; /** * TinyInternalFrameTitlePane is not an UI-delegate but a JComponent. * * @version 1.0 * @author Hans Bickel */ public class TinyInternalFrameTitlePane extends BasicInternalFrameTitlePane implements LayoutManager { protected boolean isPalette = false; /** * The buttons width, calculated at runtime. */ private int buttonsWidth; /** * Installs some default values. * Reads the internalframe title height from the ui defaults table. */ protected void installDefaults() { super.installDefaults(); frame.setFrameIcon(UIManager.getDefaults().getIcon("InternalFrame.icon")); } protected PropertyChangeListener createPropertyChangeListener() { return new TinyPropertyChangeHandler(); } /** * This constructor creates a title pane for the given internal frame * instance. * * @param frame The internal frame that needs a title pane. */ public TinyInternalFrameTitlePane(JInternalFrame frame) { super(frame); } protected void paintTitleBackground(Graphics g) { } public boolean isFrameSelected() { return frame.isSelected(); } public boolean isFrameMaximized() { return frame.isMaximum(); } /** * Paints this component. * * @param g The graphics context to use. */ public void paintComponent(Graphics g) { if(Theme.frameIsTransparent[Theme.derivedStyle[Theme.style]]) { frame.setOpaque(false); } boolean leftToRight = frame.getComponentOrientation().isLeftToRight(); boolean isSelected = frame.isSelected(); int width = getWidth(); int height = getHeight(); Color foreground = MetalLookAndFeel.getWindowTitleInactiveForeground(); int titleLength = 0; int xOffset = leftToRight ? 2 : width - 2; String frameTitle = frame.getTitle(); Icon icon = frame.getFrameIcon(); if(icon != null) { int iconY = Math.round((height - icon.getIconHeight()) / 2.0f); if(!leftToRight) { xOffset -= icon.getIconWidth(); } if(Theme.derivedStyle[Theme.style] == Theme.W99_STYLE) { iconY += 1; } icon.paintIcon(frame, g, xOffset, iconY); xOffset += leftToRight ? icon.getIconWidth() + 2 : -2; } if(frameTitle != null) { Font f = getFont(); g.setFont(f); FontMetrics fm = g.getFontMetrics(); titleLength = fm.stringWidth(frameTitle); int yOffset = ((height - fm.getHeight()) / 2) + fm.getAscent() + 1; if(!leftToRight) xOffset -= titleLength; if(isSelected) { g.setColor(Theme.frameTitleColor[Theme.style].getColor()); g.drawString(frameTitle, xOffset, yOffset); xOffset += leftToRight ? titleLength + 2 : -2; } else { // for an inactive window g.setColor(Theme.frameTitleDisabledColor[Theme.style].getColor()); g.drawString(frameTitle, xOffset, yOffset); xOffset += leftToRight ? titleLength + 2 : -2; } } } /** * Creates the layout manager for the title pane. * * @return The layout manager for the title pane. */ protected LayoutManager createLayout() { return this; } protected void addSubComponents() { super.addSubComponents(); // if(menuBar != null) { // menuBar.setOpaque(false); // } } protected void setButtonIcons() { } /** * This listener is added to the maximize, minimize and close button to * manage the rollover status of the buttons * */ class RolloverListener implements MouseListener { JButton button; Action action; public RolloverListener(JButton b, Action a) { button = b; action = a; } public void mouseClicked(MouseEvent e) { action.actionPerformed(new ActionEvent(this, Event.ACTION_EVENT, button.getText())); } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { button.getModel().setRollover(true); if(!button.isEnabled()) { button.setEnabled(true); } button.repaint(); } public void mouseExited(MouseEvent e) { button.getModel().setRollover(false); if(!frame.isSelected()) { button.setEnabled(false); } button.repaint(); } } static TinyWindowButtonUI iconButtonUI; static TinyWindowButtonUI maxButtonUI; static TinyWindowButtonUI closeButtonUI; /** * Creates the buttons of the title pane and initilizes their actions. */ protected void createButtons() { if(iconButtonUI == null) { iconButtonUI = TinyWindowButtonUI.createButtonUIForType(TinyWindowButtonUI.MINIMIZE); maxButtonUI = TinyWindowButtonUI.createButtonUIForType(TinyWindowButtonUI.MAXIMIZE); closeButtonUI = TinyWindowButtonUI.createButtonUIForType(TinyWindowButtonUI.CLOSE); } iconButton = new SpecialUIButton(iconButtonUI); iconButton.addActionListener(iconifyAction); iconButton.setRolloverEnabled(true); iconButton.addMouseListener(new RolloverListener(iconButton, iconifyAction)); maxButton = new SpecialUIButton(maxButtonUI); maxButton.addActionListener(maximizeAction); maxButton.setRolloverEnabled(true); maxButton.addMouseListener(new RolloverListener(maxButton, maximizeAction)); closeButton = new SpecialUIButton(closeButtonUI); closeButton.addActionListener(closeAction); closeButton.setRolloverEnabled(true); closeButton.addMouseListener(new RolloverListener(closeButton, closeAction)); iconButton.putClientProperty("externalFrameButton", Boolean.FALSE); maxButton.putClientProperty("externalFrameButton", Boolean.FALSE); closeButton.putClientProperty("externalFrameButton", Boolean.FALSE); iconButton.getAccessibleContext().setAccessibleName(UIManager.getString("InternalFrameTitlePane.iconifyButtonAccessibleName")); maxButton.getAccessibleContext().setAccessibleName(UIManager.getString("InternalFrameTitlePane.maximizeButtonAccessibleName")); closeButton.getAccessibleContext().setAccessibleName(UIManager.getString("InternalFrameTitlePane.closeButtonAccessibleName")); if(frame.isSelected()) { activate(); } else { deactivate(); } } /** * Paints the title pane for a palette. * * @param g The graphics context to use. */ public void paintPalette(Graphics g) { } /** * Adds the specified component with the specified name to the layout. * * @param name the component name * @param mainColor the component to be added */ public void addLayoutComponent(String name, Component c) { } /** * Removes the specified component from the layout. * * @param mainColor the component to be removed */ public void removeLayoutComponent(Component c) { } /** * Calculates the preferred size dimensions for the specified * panel given the components in the specified parent container. * * @param mainColor the component to be laid out */ public Dimension preferredLayoutSize(Container c) { return getPreferredSize(c); } /** * Gets the preferred size of the given container. * * @return The preferred size of the given container. */ public Dimension getPreferredSize(Container c) { isPalette = (frame.getClientProperty("isPalette") == Boolean.TRUE); // width. int width = 22; if(frame.isClosable()) { width += 19; } if(frame.isMaximizable()) { width += 19; } if(frame.isIconifiable()) { width += 19; } FontMetrics fm = getFontMetrics(getFont()); String frameTitle = frame.getTitle(); int title_w = frameTitle != null ? fm.stringWidth(frameTitle) : 0; int title_length = frameTitle != null ? frameTitle.length() : 0; // Leave room for three characters in the title. if(title_length > 3) { int subtitle_w = fm.stringWidth(frameTitle.substring(0, 3) + "..."); width += (title_w < subtitle_w) ? title_w : subtitle_w; } else { width += title_w; } // height int height = (isPalette ? Theme.framePaletteTitleHeight[Theme.derivedStyle[Theme.style]] : Theme.frameInternalTitleHeight[Theme.derivedStyle[Theme.style]]); Dimension dim = new Dimension(width, height); // Take into account the border insets if any. if(getBorder() != null) { Insets insets = getBorder().getBorderInsets(c); dim.height += insets.top + insets.bottom; dim.width += insets.left + insets.right; } return dim; } /** * The minimum size of the frame. * This is used, for example, during resizing to * find the minimum allowable size. * Providing at least some minimum size fixes a bug * which breaks horizontal resizing. * <b>Note</b>: the Motif plaf allows for a 0,0 min size, * but we provide a reasonable minimum here. * <b>Future</b>: calculate min size based upon contents. */ public Dimension getMinimumSize() { isPalette = (frame.getClientProperty("isPalette") == Boolean.TRUE); int height = (isPalette ? Theme.framePaletteTitleHeight[Theme.derivedStyle[Theme.style]] : Theme.frameInternalTitleHeight[Theme.derivedStyle[Theme.style]]); return new Dimension(TinyLookAndFeel.MINIMUM_INTERNAL_FRAME_WIDTH, height); } /** * Calculates the minimum size dimensions for the specified * panel given the components in the specified parent container. */ public Dimension minimumLayoutSize(Container c) { return preferredLayoutSize(c); } public void setPalette(boolean b) { isPalette = b; } public boolean isPalette() { return isPalette; } /** * Lays out the container in the specified panel. * * @param c the component which needs to be laid out */ public void layoutContainer(Container c) { isPalette = (frame.getClientProperty("isPalette") == Boolean.TRUE); boolean leftToRight = frame.getComponentOrientation().isLeftToRight(); int buttonHeight = closeButton.getPreferredSize().height; int w = getWidth(); int x = leftToRight ? w : 0; int y = (getHeight() - buttonHeight) / 2 + 1; int spacing; if(Theme.derivedStyle[Theme.style] == Theme.W99_STYLE) { y += 1; } int buttonWidth = 0; if(isPalette) { buttonWidth = Theme.framePaletteButtonSize[Theme.derivedStyle[Theme.style]].width; } else { buttonWidth = Theme.frameInternalButtonSize[Theme.derivedStyle[Theme.style]].width; } if(frame.isClosable()) { spacing = 2; x += leftToRight ? -spacing - buttonWidth : spacing; closeButton.setBounds(x, y, buttonWidth, buttonHeight); if(!leftToRight) x += (buttonWidth); } if(frame.isMaximizable()) { spacing = 2; x += leftToRight ? -spacing - buttonWidth : spacing; maxButton.setBounds(x, y, buttonWidth, buttonHeight); if(!leftToRight) x += buttonWidth; } if(frame.isIconifiable()) { spacing = (frame.isMaximizable() && Theme.style == Theme.W99_STYLE) ? 0 : 2; x += leftToRight ? -spacing - buttonWidth : spacing; iconButton.setBounds(x, y, buttonWidth, buttonHeight); if(!leftToRight) x += buttonWidth; } buttonsWidth = leftToRight ? w - x : x; } public void activate() { closeButton.setEnabled(true); iconButton.setEnabled(true); maxButton.setEnabled(true); } public void deactivate() { closeButton.setEnabled(false); iconButton.setEnabled(false); maxButton.setEnabled(false); } /** * @see java.awt.Component#getFont() */ public Font getFont() { Font f = null; if(isPalette) { f = UIManager.getFont("InternalFrame.paletteTitleFont"); } else { f = UIManager.getFont("InternalFrame.normalTitleFont"); } if(f == null) { f = new Font("SansSerife", Font.BOLD, 12); } return f; } class TinyPropertyChangeHandler extends BasicInternalFrameTitlePane.PropertyChangeHandler { public void propertyChange(PropertyChangeEvent evt) { String prop = (String)evt.getPropertyName(); if( prop.equals(JInternalFrame.IS_SELECTED_PROPERTY) ) { Boolean b = (Boolean)evt.getNewValue(); iconButton.putClientProperty("paintActive", b); closeButton.putClientProperty("paintActive", b); maxButton.putClientProperty("paintActive", b); } // else if("JInternalFrame.messageType".equals(prop)) { // updateOptionPaneState(); // frame.repaint(); // } super.propertyChange(evt); } } }