You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
11 KiB
359 lines
11 KiB
/*
|
|
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package javax.swing.plaf.synth;
|
|
|
|
|
|
import java.awt.*;
|
|
import java.awt.event.*;
|
|
import java.beans.*;
|
|
import java.util.*;
|
|
import javax.swing.*;
|
|
import javax.swing.plaf.*;
|
|
import javax.swing.plaf.basic.*;
|
|
|
|
|
|
/**
|
|
* Provides the Synth L&F UI delegate for
|
|
* {@link javax.swing.JSplitPane}.
|
|
*
|
|
* @author Scott Violet
|
|
* @since 1.7
|
|
*/
|
|
public class SynthSplitPaneUI extends BasicSplitPaneUI
|
|
implements PropertyChangeListener, SynthUI {
|
|
/**
|
|
* Keys to use for forward focus traversal when the JComponent is
|
|
* managing focus.
|
|
*/
|
|
private static Set<KeyStroke> managingFocusForwardTraversalKeys;
|
|
|
|
/**
|
|
* Keys to use for backward focus traversal when the JComponent is
|
|
* managing focus.
|
|
*/
|
|
private static Set<KeyStroke> managingFocusBackwardTraversalKeys;
|
|
|
|
/**
|
|
* Style for the JSplitPane.
|
|
*/
|
|
private SynthStyle style;
|
|
/**
|
|
* Style for the divider.
|
|
*/
|
|
private SynthStyle dividerStyle;
|
|
|
|
|
|
/**
|
|
* Creates a new SynthSplitPaneUI instance
|
|
*
|
|
* @param x component to create UI object for
|
|
* @return the UI object
|
|
*/
|
|
public static ComponentUI createUI(JComponent x) {
|
|
return new SynthSplitPaneUI();
|
|
}
|
|
|
|
/**
|
|
* Installs the UI defaults.
|
|
*/
|
|
@Override
|
|
protected void installDefaults() {
|
|
updateStyle(splitPane);
|
|
|
|
setOrientation(splitPane.getOrientation());
|
|
setContinuousLayout(splitPane.isContinuousLayout());
|
|
|
|
resetLayoutManager();
|
|
|
|
/* Install the nonContinuousLayoutDivider here to avoid having to
|
|
add/remove everything later. */
|
|
if(nonContinuousLayoutDivider == null) {
|
|
setNonContinuousLayoutDivider(
|
|
createDefaultNonContinuousLayoutDivider(),
|
|
true);
|
|
} else {
|
|
setNonContinuousLayoutDivider(nonContinuousLayoutDivider, true);
|
|
}
|
|
|
|
// focus forward traversal key
|
|
if (managingFocusForwardTraversalKeys==null) {
|
|
managingFocusForwardTraversalKeys = new HashSet<KeyStroke>();
|
|
managingFocusForwardTraversalKeys.add(
|
|
KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
|
|
}
|
|
splitPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
|
|
managingFocusForwardTraversalKeys);
|
|
// focus backward traversal key
|
|
if (managingFocusBackwardTraversalKeys==null) {
|
|
managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>();
|
|
managingFocusBackwardTraversalKeys.add(
|
|
KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
|
|
}
|
|
splitPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
|
|
managingFocusBackwardTraversalKeys);
|
|
}
|
|
|
|
private void updateStyle(JSplitPane splitPane) {
|
|
SynthContext context = getContext(splitPane, Region.SPLIT_PANE_DIVIDER,
|
|
ENABLED);
|
|
SynthStyle oldDividerStyle = dividerStyle;
|
|
dividerStyle = SynthLookAndFeel.updateStyle(context, this);
|
|
context.dispose();
|
|
|
|
context = getContext(splitPane, ENABLED);
|
|
SynthStyle oldStyle = style;
|
|
|
|
style = SynthLookAndFeel.updateStyle(context, this);
|
|
|
|
if (style != oldStyle) {
|
|
Object value = style.get(context, "SplitPane.size");
|
|
if (value == null) {
|
|
value = Integer.valueOf(6);
|
|
}
|
|
LookAndFeel.installProperty(splitPane, "dividerSize", value);
|
|
|
|
value = style.get(context, "SplitPane.oneTouchExpandable");
|
|
if (value != null) {
|
|
LookAndFeel.installProperty(splitPane, "oneTouchExpandable", value);
|
|
}
|
|
|
|
if (divider != null) {
|
|
splitPane.remove(divider);
|
|
divider.setDividerSize(splitPane.getDividerSize());
|
|
}
|
|
if (oldStyle != null) {
|
|
uninstallKeyboardActions();
|
|
installKeyboardActions();
|
|
}
|
|
}
|
|
if (style != oldStyle || dividerStyle != oldDividerStyle) {
|
|
// Only way to force BasicSplitPaneDivider to reread the
|
|
// necessary properties.
|
|
if (divider != null) {
|
|
splitPane.remove(divider);
|
|
}
|
|
divider = createDefaultDivider();
|
|
divider.setBasicSplitPaneUI(this);
|
|
splitPane.add(divider, JSplitPane.DIVIDER);
|
|
}
|
|
context.dispose();
|
|
}
|
|
|
|
/**
|
|
* Installs the event listeners for the UI.
|
|
*/
|
|
@Override
|
|
protected void installListeners() {
|
|
super.installListeners();
|
|
splitPane.addPropertyChangeListener(this);
|
|
}
|
|
|
|
/**
|
|
* Uninstalls the UI defaults.
|
|
*/
|
|
@Override
|
|
protected void uninstallDefaults() {
|
|
SynthContext context = getContext(splitPane, ENABLED);
|
|
|
|
style.uninstallDefaults(context);
|
|
context.dispose();
|
|
style = null;
|
|
|
|
context = getContext(splitPane, Region.SPLIT_PANE_DIVIDER, ENABLED);
|
|
dividerStyle.uninstallDefaults(context);
|
|
context.dispose();
|
|
dividerStyle = null;
|
|
|
|
super.uninstallDefaults();
|
|
}
|
|
|
|
|
|
/**
|
|
* Uninstalls the event listeners from the UI.
|
|
*/
|
|
@Override
|
|
protected void uninstallListeners() {
|
|
super.uninstallListeners();
|
|
splitPane.removePropertyChangeListener(this);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public SynthContext getContext(JComponent c) {
|
|
return getContext(c, SynthLookAndFeel.getComponentState(c));
|
|
}
|
|
|
|
private SynthContext getContext(JComponent c, int state) {
|
|
return SynthContext.getContext(c, style, state);
|
|
}
|
|
|
|
SynthContext getContext(JComponent c, Region region) {
|
|
return getContext(c, region, getComponentState(c, region));
|
|
}
|
|
|
|
private SynthContext getContext(JComponent c, Region region, int state) {
|
|
if (region == Region.SPLIT_PANE_DIVIDER) {
|
|
return SynthContext.getContext(c, region, dividerStyle, state);
|
|
}
|
|
return SynthContext.getContext(c, region, style, state);
|
|
}
|
|
|
|
private int getComponentState(JComponent c, Region subregion) {
|
|
int state = SynthLookAndFeel.getComponentState(c);
|
|
|
|
if (divider.isMouseOver()) {
|
|
state |= MOUSE_OVER;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void propertyChange(PropertyChangeEvent e) {
|
|
if (SynthLookAndFeel.shouldUpdateStyle(e)) {
|
|
updateStyle((JSplitPane)e.getSource());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates the default divider.
|
|
*/
|
|
@Override
|
|
public BasicSplitPaneDivider createDefaultDivider() {
|
|
SynthSplitPaneDivider divider = new SynthSplitPaneDivider(this);
|
|
|
|
divider.setDividerSize(splitPane.getDividerSize());
|
|
return divider;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
protected Component createDefaultNonContinuousLayoutDivider() {
|
|
return new Canvas() {
|
|
public void paint(Graphics g) {
|
|
paintDragDivider(g, 0, 0, getWidth(), getHeight());
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Notifies this UI delegate to repaint the specified component.
|
|
* This method paints the component background, then calls
|
|
* the {@link #paint(SynthContext,Graphics)} method.
|
|
*
|
|
* <p>In general, this method does not need to be overridden by subclasses.
|
|
* All Look and Feel rendering code should reside in the {@code paint} method.
|
|
*
|
|
* @param g the {@code Graphics} object used for painting
|
|
* @param c the component being painted
|
|
* @see #paint(SynthContext,Graphics)
|
|
*/
|
|
@Override
|
|
public void update(Graphics g, JComponent c) {
|
|
SynthContext context = getContext(c);
|
|
|
|
SynthLookAndFeel.update(context, g);
|
|
context.getPainter().paintSplitPaneBackground(context,
|
|
g, 0, 0, c.getWidth(), c.getHeight());
|
|
paint(context, g);
|
|
context.dispose();
|
|
}
|
|
|
|
/**
|
|
* Paints the specified component according to the Look and Feel.
|
|
* <p>This method is not used by Synth Look and Feel.
|
|
* Painting is handled by the {@link #paint(SynthContext,Graphics)} method.
|
|
*
|
|
* @param g the {@code Graphics} object used for painting
|
|
* @param c the component being painted
|
|
* @see #paint(SynthContext,Graphics)
|
|
*/
|
|
@Override
|
|
public void paint(Graphics g, JComponent c) {
|
|
SynthContext context = getContext(c);
|
|
|
|
paint(context, g);
|
|
context.dispose();
|
|
}
|
|
|
|
/**
|
|
* Paints the specified component. This implementation does nothing.
|
|
*
|
|
* @param context context for the component being painted
|
|
* @param g the {@code Graphics} object used for painting
|
|
* @see #update(Graphics,JComponent)
|
|
*/
|
|
protected void paint(SynthContext context, Graphics g) {
|
|
// This is done to update package private variables in
|
|
// BasicSplitPaneUI
|
|
super.paint(g, splitPane);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void paintBorder(SynthContext context, Graphics g, int x,
|
|
int y, int w, int h) {
|
|
context.getPainter().paintSplitPaneBorder(context, g, x, y, w, h);
|
|
}
|
|
|
|
private void paintDragDivider(Graphics g, int x, int y, int w, int h) {
|
|
SynthContext context = getContext(splitPane,Region.SPLIT_PANE_DIVIDER);
|
|
context.setComponentState(((context.getComponentState() | MOUSE_OVER) ^
|
|
MOUSE_OVER) | PRESSED);
|
|
Shape oldClip = g.getClip();
|
|
g.clipRect(x, y, w, h);
|
|
context.getPainter().paintSplitPaneDragDivider(context, g, x, y, w, h,
|
|
splitPane.getOrientation());
|
|
g.setClip(oldClip);
|
|
context.dispose();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void finishedPaintingChildren(JSplitPane jc, Graphics g) {
|
|
if(jc == splitPane && getLastDragLocation() != -1 &&
|
|
!isContinuousLayout() && !draggingHW) {
|
|
if(jc.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
|
|
paintDragDivider(g, getLastDragLocation(), 0, dividerSize - 1,
|
|
splitPane.getHeight() - 1);
|
|
} else {
|
|
paintDragDivider(g, 0, getLastDragLocation(),
|
|
splitPane.getWidth() - 1, dividerSize - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|