/** * 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.JOutlookBar; import com.l2fprod.common.swing.PercentLayout; import com.l2fprod.common.swing.PercentLayoutAnimator; import com.l2fprod.common.swing.plaf.OutlookBarUI; import com.l2fprod.common.util.JVM; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.ButtonUI; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicTabbedPaneUI; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.*; import java.util.List; /** * BasicOutlookBarUI. <br> */ public class BasicOutlookBarUI extends BasicTabbedPaneUI implements OutlookBarUI { private static final String BUTTON_ORIGINAL_FOREGROUND = "TabButton/foreground"; private static final String BUTTON_ORIGINAL_BACKGROUND = "TabButton/background"; public static ComponentUI createUI(JComponent c) { return new BasicOutlookBarUI(); } private ContainerListener tabListener; private Map buttonToTab; private Map tabToButton; private Component nextVisibleComponent; private PercentLayoutAnimator animator; public JScrollPane makeScrollPane(Component component) { // the component is not scrollable, wraps it in a ScrollableJPanel JScrollPane scroll = new JScrollPane(); scroll.setBorder(BorderFactory.createEmptyBorder()); if (component instanceof Scrollable) { scroll.getViewport().setView(component); } else { scroll.getViewport().setView(new ScrollableJPanel(component)); } scroll.setOpaque(false); scroll.getViewport().setOpaque(false); return scroll; } protected void installDefaults() { super.installDefaults(); TabLayout layout = new TabLayout(); tabPane.setLayout(layout); // ensure constraints is correct for existing components layout.setLayoutConstraints(tabPane); updateTabLayoutOrientation(); buttonToTab = new HashMap(); tabToButton = new HashMap(); LookAndFeel.installBorder(tabPane, "OutlookBar.border"); LookAndFeel.installColors(tabPane, "OutlookBar.background", "OutlookBar.foreground"); tabPane.setOpaque(true); // add buttons for the current components already added in this panel Component[] components = tabPane.getComponents(); for (int i = 0, c = components.length; i < c; i++) { tabAdded(components[i]); } } protected void uninstallDefaults() { // remove all buttons created for components List tabs = new ArrayList(buttonToTab.values()); for (Iterator iter = tabs.iterator(); iter.hasNext(); ) { Component tab = (Component) iter.next(); tabRemoved(tab); } super.uninstallDefaults(); } protected void installListeners() { tabPane.addContainerListener(tabListener = createTabListener()); tabPane.addPropertyChangeListener(propertyChangeListener = createPropertyChangeListener()); tabPane.addChangeListener(tabChangeListener = createChangeListener()); } protected ContainerListener createTabListener() { return new ContainerTabHandler(); } protected PropertyChangeListener createPropertyChangeListener() { return new PropertyChangeHandler(); } protected ChangeListener createChangeListener() { return new ChangeHandler(); } protected void uninstallListeners() { tabPane.removeChangeListener(tabChangeListener); tabPane.removePropertyChangeListener(propertyChangeListener); tabPane.removeContainerListener(tabListener); } public Rectangle getTabBounds(JTabbedPane pane, int index) { Component tab = pane.getComponentAt(index); return tab.getBounds(); } public int getTabRunCount(JTabbedPane pane) { return 0; } public int tabForCoordinate(JTabbedPane pane, int x, int y) { int index = -1; for (int i = 0, c = pane.getTabCount(); i < c; i++) { if (pane.getComponentAt(i).contains(x, y)) { index = i; break; } } return index; } protected int indexOfComponent(Component component) { int index = -1; Component[] components = tabPane.getComponents(); for (int i = 0; i < components.length; i++) { if (components[i] == component) { index = i; break; } } return index; } protected TabButton createTabButton() { TabButton button = new TabButton(); button.setOpaque(true); return button; } protected void tabAdded(final Component newTab) { TabButton button = (TabButton) tabToButton.get(newTab); if (button == null) { button = createTabButton(); // save the button original color, // later they would be restored if the button colors are not customized on // the OutlookBar button.putClientProperty(BUTTON_ORIGINAL_FOREGROUND, button.getForeground()); button.putClientProperty(BUTTON_ORIGINAL_BACKGROUND, button.getBackground()); buttonToTab.put(button, newTab); tabToButton.put(newTab, button); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final Component current = getVisibleComponent(); Component target = newTab; // animate the tabPane if there is a current tab selected and if the // tabPane allows animation if (((JOutlookBar) tabPane).isAnimated() && current != target && current != null && target != null) { if (animator != null) { animator.stop(); } animator = new PercentLayoutAnimator(tabPane, (PercentLayout) tabPane.getLayout()) { protected void complete() { super.complete(); tabPane.setSelectedComponent(newTab); nextVisibleComponent = null; // ensure the no longer visible component has its constraint // reset to 100% in the case it becomes visible again without // animation if (current.getParent() == tabPane) { ((PercentLayout) tabPane.getLayout()).setConstraint(current, "100%"); } } }; nextVisibleComponent = newTab; animator.setTargetPercent(current, 1.0f, 0.0f); animator.setTargetPercent(newTab, 0.0f, 1.0f); animator.start(); } else { nextVisibleComponent = null; tabPane.setSelectedComponent(newTab); } } }); } else { // the tab is already in the list, remove the button, it will be // added again later tabPane.remove(button); } // update the button with the tab information updateTabButtonAt(tabPane.indexOfComponent(newTab)); int index = indexOfComponent(newTab); tabPane.add(button, index); // workaround for nullpointerexception in setRolloverTab // introduced by J2SE 5 if (JVM.current().isOneDotFive()) { assureRectsCreated(tabPane.getTabCount()); } } protected void tabRemoved(Component removedTab) { TabButton button = (TabButton) tabToButton.get(removedTab); tabPane.remove(button); buttonToTab.remove(button); tabToButton.remove(removedTab); } /** * Called whenever a property of a tab is changed * * @param index */ protected void updateTabButtonAt(int index) { TabButton button = buttonForTab(index); button.setText(tabPane.getTitleAt(index)); button.setIcon(tabPane.getIconAt(index)); button.setDisabledIcon(tabPane.getDisabledIconAt(index)); Color background = tabPane.getBackgroundAt(index); if (background == null) { background = (Color) button.getClientProperty(BUTTON_ORIGINAL_BACKGROUND); } button.setBackground(background); Color foreground = tabPane.getForegroundAt(index); if (foreground == null) { foreground = (Color) button.getClientProperty(BUTTON_ORIGINAL_FOREGROUND); } button.setForeground(foreground); button.setToolTipText(tabPane.getToolTipTextAt(index)); button.setDisplayedMnemonicIndex(tabPane.getDisplayedMnemonicIndexAt(index)); button.setMnemonic(tabPane.getMnemonicAt(index)); button.setEnabled(tabPane.isEnabledAt(index)); button.setHorizontalAlignment(((JOutlookBar) tabPane).getAlignmentAt(index)); } protected TabButton buttonForTab(int index) { Component component = tabPane.getComponentAt(index); return (TabButton) tabToButton.get(component); } class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent e) { JTabbedPane tabPane = (JTabbedPane) e.getSource(); tabPane.revalidate(); tabPane.repaint(); } } class PropertyChangeHandler implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent e) { //JTabbedPane pane = (JTabbedPane)e.getSource(); String name = e.getPropertyName(); if ("tabPropertyChangedAtIndex".equals(name)) { int index = ((Integer) e.getNewValue()).intValue(); updateTabButtonAt(index); } else if ("tabPlacement".equals(name)) { updateTabLayoutOrientation(); } } } protected void updateTabLayoutOrientation() { TabLayout layout = (TabLayout) tabPane.getLayout(); int placement = tabPane.getTabPlacement(); if (placement == JTabbedPane.TOP || placement == JTabbedPane.BOTTOM) { layout.setOrientation(PercentLayout.HORIZONTAL); } else { layout.setOrientation(PercentLayout.VERTICAL); } } /** * Manages tabs being added or removed */ class ContainerTabHandler extends ContainerAdapter { public void componentAdded(ContainerEvent e) { if (!(e.getChild() instanceof UIResource)) { Component newTab = e.getChild(); tabAdded(newTab); } } public void componentRemoved(ContainerEvent e) { if (!(e.getChild() instanceof UIResource)) { Component oldTab = e.getChild(); tabRemoved(oldTab); } } } /** * Layout for the tabs, buttons get preferred size, tabs get all */ protected class TabLayout extends PercentLayout { public void addLayoutComponent(Component component, Object constraints) { if (constraints == null) { if (component instanceof TabButton) { super.addLayoutComponent(component, ""); } else { super.addLayoutComponent(component, "100%"); } } else { super.addLayoutComponent(component, constraints); } } public void setLayoutConstraints(Container parent) { Component[] components = parent.getComponents(); for (int i = 0, c = components.length; i < c; i++) { if (!(components[i] instanceof TabButton)) { super.addLayoutComponent(components[i], "100%"); } } } public void layoutContainer(Container parent) { int selectedIndex = tabPane.getSelectedIndex(); Component visibleComponent = getVisibleComponent(); if (selectedIndex < 0) { if (visibleComponent != null) { // The last tab was removed, so remove the component setVisibleComponent(null); } } else { Component selectedComponent = tabPane.getComponentAt(selectedIndex); boolean shouldChangeFocus = false; // In order to allow programs to use a single component // as the display for multiple tabs, we will not change // the visible compnent if the currently selected tab // has a null component. This is a bit dicey, as we don't // explicitly state we support this in the spec, but since // programs are now depending on this, we're making it work. // if (selectedComponent != null) { if (selectedComponent != visibleComponent && visibleComponent != null) { // get the current focus owner Component currentFocusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); // check if currentFocusOwner is a descendant of visibleComponent if (currentFocusOwner != null && SwingUtilities.isDescendingFrom(currentFocusOwner, visibleComponent)) { shouldChangeFocus = true; } } setVisibleComponent(selectedComponent); // make sure only the selected component is visible Component[] components = parent.getComponents(); for (int i = 0; i < components.length; i++) { if (!(components[i] instanceof UIResource) && components[i].isVisible() && components[i] != selectedComponent) { components[i].setVisible(false); setConstraint(components[i], "*"); } } if (BasicOutlookBarUI.this.nextVisibleComponent != null) { BasicOutlookBarUI.this.nextVisibleComponent.setVisible(true); } } super.layoutContainer(parent); if (shouldChangeFocus) { if (!requestFocusForVisibleComponent0()) { tabPane.requestFocus(); } } } } } // PENDING(fred) JDK 1.5 may have this method from superclass @SuppressWarnings("deprecation") protected boolean requestFocusForVisibleComponent0() { Component visibleComponent = getVisibleComponent(); if (visibleComponent.isFocusable()) { visibleComponent.requestFocus(); return true; } else if (visibleComponent instanceof JComponent) { if (((JComponent) visibleComponent).requestDefaultFocus()) { return true; } } return false; } protected static class TabButton extends JButton implements UIResource { public TabButton() {} public TabButton(ButtonUI ui) { setUI(ui); } } // // // /** * Overriden to return an empty adapter, the default listener was * just implementing the tab selection mechanism */ protected MouseListener createMouseListener() { return new MouseAdapter() {}; } /** * Wraps any component in a Scrollable JPanel so it can work * correctly within a viewport */ private static class ScrollableJPanel extends JPanel implements Scrollable { public ScrollableJPanel(Component component) { setLayout(new BorderLayout(0, 0)); add("Center", component); setOpaque(false); } public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { return 16; } public Dimension getPreferredScrollableViewportSize() { return (super.getPreferredSize()); } public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { return 16; } public boolean getScrollableTracksViewportWidth() { return true; } public boolean getScrollableTracksViewportHeight() { return false; } } // // Override all paint methods of the BasicTabbedPaneUI to do nothing // public void paint(Graphics g, JComponent c) {} protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {} protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected) {} protected void paintIcon(Graphics g, int tabPlacement, int tabIndex, Icon icon, Rectangle iconRect, boolean isSelected) {} protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect) {} protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex) {} protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) {} protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) {} protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) {} }