org.openide.awt.SplittedPanel Maven / Gradle / Ivy
Go to download
The NetBeans Platform is a generic base for desktop applications. It provides the services common
to almost all large desktop applications: window management, menus, settings and storage, an update
manager, and file access. Get a head start by reusing these standard components, allowing you to
concentrate fully on your application's business logic.
The newest version!
/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.awt;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.ResourceBundle;
import java.util.Vector;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.*;
import javax.swing.border.*;
import org.openide.ErrorManager;
import org.openide.util.NbBundle;
import org.openide.awt.JPopupMenuPlus;
/** The SplittedPanel widget is a Panel that can contain one or two components and
* place them side-by-side vertically or horizontally with a splitter in the middle.
* User can move the split point by dragging the splitter with mouse.
* The two components are accessed by add/remove methods with constraints value
* ADD_SPLITTER, ADD_FIRST, ADD_SECOND, ....
* The split position could be either absolute or proportional (according to the
* "Absolute" property setting) - in thwe absolute mode the split point remains same
* when resizing (i.e. the left/top component keeps its size and only the
* right/bottom component resizes), while in the proportional mode the splitPosition
* is a percentage of the width/height assigned to the left/top component.
*
* Property Property Type Description
* SplitType int The type of the splitting - HORIZONTAL, VERTICAL or NONE
* SplitPosition int The position of the split point - either absolute position or number of percents
* according to the "Absolute" property settings, could be one of FIRST_PREFERRED or
* SECOND_PREFERRED, which means that the split point should be placed so that
* the first(left/top) resp. second (bottom/rignt) is sized according to its preferredSize
* (in this case the Absolute property setting is ignored)
* SplitterType int The type of the component that renders the splitter - DEFAULT_SPLITTER, RAISED_SPLITTER,
* EMPTY_SPLITTER.
* SplitterComponent Component The component that renders the splitter. A custom component can be provided in addition to EMPTY_SPLITTER and RAISED-SPLITTER using this method.
* SplitAbsolute boolean if true then the meaning of the SplitPosition is absolute points,
* otherwise the SplitPosition is a number of percents
* SplitDragable boolean if true then the split point can be dragged using a mouse,
* otherwise the SplitPosition is fixed
* SplitTypeChangeEnabled boolean if true then the split type can be changed via popup menu commands
* SwapPanesEnabled boolean if true then the panes can be swapped via popup menu command
*
*
* @author Ian Formanek
* @deprecated This class does nothing interesting that cannot be done with a JSplitPane.
* Use a JSplitPane instead.
*/
public class SplittedPanel extends JComponent implements Accessible {
/** generated Serialized Version UID */
static final long serialVersionUID = 5058424218525927233L;
/** constant for no split - only the first (left/top) component will be shown */
public final static int NONE = 0;
/** constant for vertical split */
public final static int VERTICAL = 1;
/** constant for horizontal split */
public final static int HORIZONTAL = 2;
/** constraints constant for adding a splitter */
public static final Object ADD_SPLITTER = new Integer(0);
/** constraints constant for adding a component to the first (left/top) pane */
public static final Object ADD_FIRST = new Integer(1);
/** constraints constant for adding a component to the second (right/bottom) pane */
public static final Object ADD_SECOND = new Integer(2);
/** constraints constant for adding a component to the left(top) pane (an alias for the ADD_FIRST constant) */
public static final Object ADD_LEFT = ADD_FIRST;
/** constraints constant for adding a component to the top(left) pane (an alias for the ADD_FIRST constant) */
public static final Object ADD_TOP = ADD_FIRST;
/** constraints constant for adding a component to the right(bottom) pane (an alias for the ADD_SECOND constant) */
public static final Object ADD_RIGHT = ADD_SECOND;
/** constraints constant for adding a component to the bottom(right) pane (an alias for the ADD_SECOND constant) */
public static final Object ADD_BOTTOM = ADD_SECOND;
/** constant for moving the split point so that the first (left/top) component is sized according to its preferredSize */
public static final int FIRST_PREFERRED = -1;
/** constant for moving the split point so that the second (right/bottom) component is sized according to its preferredSize */
public static final int SECOND_PREFERRED = -2;
/** constant for splitter component types - raised splitter*/
public static final int RAISED_SPLITTER = 0;
/** constant for splitter component types - empty splitter */
public static final int EMPTY_SPLITTER = 1;
/** constant for splitter component types - default splitter (raised)*/
public static final int DEFAULT_SPLITTER = RAISED_SPLITTER;
/** Save the last preferred setting (first or second). Double click reset the splitPosition to this value */
private int resetPosition = FIRST_PREFERRED;
/** Is popup menu enabled?*/
private Boolean popupMenuEnabled;
/** Constructs a new empty SplittedPanel with no spliting.
*/
public SplittedPanel () {
splitter = new DefaultSplitter (getDefaultSplitterSize());
accessibleContext = null;
setLayout (new SplitLayout());
add(splitter, ADD_SPLITTER);
init();
RuntimeException rte = new RuntimeException(
"SplittedPanel is deprecated. Please use JSplitPane instead"); //NOI18N
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, rte);
}
/** Initializes the SplittedPanel */
private void init() {
setSplitterCursor();
mouseAdapter = new MouseListenerAdapter();
if (dragable) {
splitter.addMouseMotionListener(mouseAdapter);
splitter.addMouseListener(mouseAdapter);
addSplitChangeListener (mouseAdapter);
}
initAccessible();
}
private boolean drawBumps;
/** Updates splitting, too. */
public void updateUI() {
super.updateUI();
updateSplitting();
Object o = UIManager.get ("nb.SplittedPanel.drawBumps");
drawBumps = Boolean.TRUE.equals (o);
}
/** Updates the visual state and layout when the split state changes. */
protected void updateSplitting() {
if (firstComponent != null && secondComponent != null) {
invalidate();
firstComponent.invalidate();
splitter.invalidate();
secondComponent.invalidate();
validate();
}
}
/** Computes component sizes after performing the flip,
* it means splitTypeChange */
protected void computeSizesAfterFlip () {
if (firstComponent == null || secondComponent == null) return;
Dimension ourSize = getSize();
int splitterSize;
switch (splitType) {
case VERTICAL:
if (ourSize.width == 0) break;
splitterSize = splitter.getPreferredSize ().height;
int newHeight = (ourSize.height - splitterSize) *
firstComponent.getSize().width / ourSize.width;
firstComponent.setSize(new Dimension(ourSize.width, newHeight));
secondComponent.setSize(new Dimension(ourSize.width,
ourSize.height - newHeight - splitterSize));
break;
case HORIZONTAL:
if (ourSize.height == 0) break;
splitterSize = splitter.getPreferredSize ().width;
int newWidth = (ourSize.width - splitterSize) *
firstComponent.getSize().height / ourSize.height;
firstComponent.setSize(new Dimension(newWidth, ourSize.height));
secondComponent.setSize(new Dimension(ourSize.width - newWidth - splitterSize,
ourSize.height));
break;
}
}
/** Updates the splitter's cursor according to the current SplittedPanel settings. */
protected void setSplitterCursor() {
if (dragable) {
if (splitType == VERTICAL)
splitter.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
else
splitter.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
}
else
splitter.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
/** Is popup menu on spliter enabled? See issue 25216.*/
private boolean isPopupMenuEnabled () {
if (popupMenuEnabled == null) {
Object o = getClientProperty ("popupMenuEnabled");
if (o instanceof Boolean)
popupMenuEnabled = (Boolean)o;
else
popupMenuEnabled = Boolean.TRUE;
}
return popupMenuEnabled.booleanValue ();
}
/** Updates the splitter's popup menu. */
protected void updatePopupMenu() {
if (popupMenu == null) {
popupMenu = new JPopupMenuPlus();
java.util.ResourceBundle awtBundle = NbBundle.getBundle (SplittedPanel.class);
popupMenu.add(verticalCMI = new JRadioButtonMenuItem(awtBundle.getString("SplittedPanelVertical")));
popupMenu.add(horizontalCMI = new JRadioButtonMenuItem(awtBundle.getString("SplittedPanelHorizontal")));
popupMenu.add(new JSeparator());
popupMenu.add(swapCMI = new JMenuItem(awtBundle.getString("SplittedPanelSwap")));
popupMenu.add(new JSeparator());
popupMenu.add(splitterCMI = new JMenuItem(awtBundle.getString("ResetSplitter")));
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (horizontalCMI.equals(e.getSource()))
setSplitType(HORIZONTAL);
else
setSplitType(VERTICAL);
}
};
verticalCMI.addActionListener(al);
horizontalCMI.addActionListener(al);
swapCMI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
swapPanes();
}
});
splitterCMI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
resetSplitter ();
}
});
}
if (splitType == VERTICAL) {
verticalCMI.setSelected(true);
horizontalCMI.setSelected(false);
}
else {
verticalCMI.setSelected(false);
horizontalCMI.setSelected(true);
}
if (splitTypeChangeEnabled) {
verticalCMI.setEnabled(true);
horizontalCMI.setEnabled(true);
}
else {
verticalCMI.setEnabled(false);
horizontalCMI.setEnabled(false);
}
if (swapPanesEnabled)
swapCMI.setEnabled(true);
else
swapCMI.setEnabled(false);
splitterCMI.setEnabled (getSplitPosition() != FIRST_PREFERRED && getSplitPosition() != SECOND_PREFERRED);
}
/** Reset split line to follow the largest name. */
private void resetSplitter () {
if (getSplitPosition() != FIRST_PREFERRED && getSplitPosition() != SECOND_PREFERRED) {
setSplitPosition(resetPosition);
if (splitterCMI!=null)
splitterCMI.setEnabled (false);
}
}
/** Swaps the panes.*/
public void swapPanes() {
if (!swapPanesEnabled) return;
if ((firstComponent == null) || (secondComponent == null)) return;
splitIsChanging = true;
panesSwapped = !panesSwapped;
if (keepSecondSame) {
keepSecondSame = false;
keepFirstSame = true;
} else if (keepFirstSame) {
keepSecondSame = true;
keepFirstSame = false;
}
Component aFirstComponent = firstComponent;
Component aSecondComponent = secondComponent;
remove(aFirstComponent);
remove(aSecondComponent);
add(aSecondComponent, ADD_FIRST);
add(aFirstComponent, ADD_SECOND);
updateSplitting();
splitIsChanging = false;
}
/** @return true if the panes are swapped, false otherwise */
public boolean getPanesSwapped() {
return panesSwapped;
}
///////////////////////////////
// Property accessor methods //
///////////////////////////////
/** Getter method for the SplitType property.
* @return Current SplitType value.
*/
public int getSplitType() {
return splitType;
}
/** Setter method for the SplitType property.
* @param value New SplitType value.
*/
public void setSplitType(int value) {
if (splitType == value) return;
int oldSplitType = splitType;
splitType = value;
if ((oldSplitType != NONE) && (splitType != NONE))
computeSizesAfterFlip();
setSplitterCursor();
updateSplitting();
updatePopupMenu();
initAccessible();
}
/** Getter method for the SplitPosition property.
* @return Current SplitPosition value.
*/
public int getSplitPosition() {
return splitPosition;
}
/** Setter method for the SplitPosition property.
* @param value New SplitPosition value.
*/
public void setSplitPosition(int value) {
if (splitPosition == value) return;
int oldValue = splitPosition;
splitPosition = value;
splitIsChanging = true;
updateSplitting();
fireSplitChange(oldValue, splitPosition);
splitIsChanging = false;
}
/** Getter method for the SplitterType property.
* @return Current SplitterType value.
* @see #EMPTY_SPLITTER
* @see #RAISED_SPLITTER
* @see #DEFAULT_SPLITTER
*/
public int getSplitterType() {
return splitterType;
}
private int getDefaultSplitterSize () {
Object o = UIManager.get ("nb.SplittedPanel.dividerSize"); //NOI18N
if (o != null) {
return ((Integer) o).intValue();
}
o = UIManager.get ("SplitPane.dividerSize"); //NOI18N
if (o != null) {
return ((Integer) o).intValue();
}
return 6;
}
/** Setter method for the SplitterType property.
* @param type New SplitterType value.
* @see #EMPTY_SPLITTER
* @see #RAISED_SPLITTER
* @see #DEFAULT_SPLITTER
*/
public void setSplitterType(int type) {
if (splitterType == type) return;
splitterType = type;
switch (splitterType) {
case EMPTY_SPLITTER:
splitter = new EmptySplitter();
break;
default:
case RAISED_SPLITTER:
splitter = new DefaultSplitter(getDefaultSplitterSize());
break;
}
add(splitter, ADD_SPLITTER);
updateSplitting();
}
/** Getter method for the SplitterComponent property.
* @return Current SplitterComponent value.
* @see #getSplitterType
*/
public Component getSplitterComponent() {
return splitter;
}
/** Setter method for the SplitterComponent property.
* @param comp New SplitterComponent value.
* @see #setSplitterType
*/
public void setSplitterComponent(Component comp) {
if (splitter == comp) return;
if (dragable) {
splitter.removeMouseMotionListener(mouseAdapter);
splitter.removeMouseListener(mouseAdapter);
}
remove (splitter);
splitter = comp;
add(splitter, ADD_SPLITTER);
if (dragable) {
splitter.addMouseMotionListener(mouseAdapter);
splitter.addMouseListener(mouseAdapter);
}
setSplitterCursor();
updateSplitting();
}
/** Getter method for the SplitAbsolute property.
* @return Current SplitAbsolute value.
*/
public boolean isSplitAbsolute() {
return absolute;
}
/** Setter method for the SplitAbsolute property.
* @param value New SplitAbsolute value.
*/
public void setSplitAbsolute(boolean value) {
if (absolute == value) return;
absolute = value;
updateSplitting();
}
/** Getter method for the SplitDragable property.
* @return Current SplitDragable value.
*/
public boolean isSplitDragable() {
return dragable;
}
/** Setter method for the Dragable property.
* @param value New Dragable value.
*/
public void setSplitDragable(boolean value) {
if (dragable == value) return;
dragable = value;
if (dragable) {
splitter.addMouseMotionListener(mouseAdapter);
splitter.addMouseListener(mouseAdapter);
}
else {
splitter.removeMouseMotionListener(mouseAdapter);
splitter.removeMouseListener(mouseAdapter);
}
setSplitterCursor();
}
/** Getter method for the ContinuousLayout property.
* @return Current ContinuousLayout value.
*/
public boolean isContinuousLayout() {
return continuousLayout;
}
/** Setter method for the ContinuousLayout property.
* @param value New ContinuousLayout value.
*/
public void setContinuousLayout(boolean value) {
continuousLayout = value;
}
/** Getter method for the KeepFirstSame property.
* @return Current KeepFirstSame value.
*/
public boolean getKeepFirstSame () {
return keepFirstSame;
}
/** Setter method for the KeepFirstSame property.
* @param value New KeepFirstSame value.
*/
public void setKeepFirstSame (boolean value) {
keepFirstSame = value;
}
/** Getter method for the KeepSecondSame property.
* @return Current KeepSecondSame value.
*/
public boolean getKeepSecondSame () {
return keepSecondSame;
}
/** Setter method for the KeepSecondSame property.
* @param value New KeepSecondSame value.
*/
public void setKeepSecondSame (boolean value) {
keepSecondSame = value;
}
/** Getter method for the SplitTypeChangeEnabled property.
* @return Current SplitTypeChangeEnabled value.
*/
public boolean isSplitTypeChangeEnabled() {
return splitTypeChangeEnabled;
}
/** Setter method for the SplitTypeChangeEnabled property.
* @param value New SplitTypeChangeEnabled value.
*/
public void setSplitTypeChangeEnabled(boolean value) {
if (splitTypeChangeEnabled == value) return;
splitTypeChangeEnabled = value;
updatePopupMenu();
}
/** Getter method for the SwapPanesEnabled property.
* @return Current SwapPanesEnabled value.
*/
public boolean isSwapPanesEnabled() {
return swapPanesEnabled;
}
/** Setter method for the SwapPanesEnabled property.
* @param value New SwapPanesEnabled value.
*/
public void setSwapPanesEnabled(boolean value) {
if (swapPanesEnabled == value) return;
swapPanesEnabled = value;
updatePopupMenu();
}
/////////////////////
// Event Listeners //
/////////////////////
/** Adds specified listener to the current set of SplitChangeListeners */
public void addSplitChangeListener(SplitChangeListener l) {
if (listeners == null)
listeners = new Vector();
listeners.addElement(l);
}
/** Removes specified listener from the current set of SplitChangeListeners */
public void removeSplitChangeListener(SplitChangeListener l) {
if (listeners == null)
return;
listeners.removeElement(l);
}
/** Fires the SplitChange event */
protected void fireSplitChange(int oldValue, int newValue) {
if (listeners == null)
return;
Vector l;
synchronized (this) {
l = (Vector)listeners.clone();
}
Enumeration en = l.elements ();
SplitChangeEvent evt = new SplitChangeEvent (this, oldValue, newValue);
while (en.hasMoreElements ()) {
SplitChangeListener scl = (SplitChangeListener) en.nextElement ();
scl.splitChanged(evt);
}
}
/* Read accessible context
* @return - accessible context
*/
public AccessibleContext getAccessibleContext () {
if(accessibleContext == null) {
accessibleContext = new AccessibleJComponent() {
public AccessibleRole getAccessibleRole() {
return AccessibleRole.SPLIT_PANE;
}
};
initAccessible();
}
return accessibleContext;
}
private static MessageFormat nameFormat = null;
private static MessageFormat descriptionFormat = null;
private void initAccessible () {
if (nameFormat == null) {
ResourceBundle bundle = NbBundle.getBundle(SplittedPanel.class);
nameFormat = new MessageFormat(bundle.getString("ACS_SplittedPanel_Name"));
}
getAccessibleContext().setAccessibleName(nameFormat.format(new Object[] {firstComponent == null || !(firstComponent instanceof Accessible) ? null : firstComponent.getAccessibleContext().getAccessibleName(),
secondComponent == null || !(secondComponent instanceof Accessible) ? null : secondComponent.getAccessibleContext().getAccessibleName()}));
if (descriptionFormat == null) {
ResourceBundle bundle = NbBundle.getBundle(SplittedPanel.class);
descriptionFormat = new MessageFormat(bundle.getString("ACS_SplittedPanel_Description"));
}
getAccessibleContext().setAccessibleDescription(descriptionFormat.format(new Object[] {firstComponent == null || !(firstComponent instanceof Accessible) ? null : firstComponent.getAccessibleContext().getAccessibleDescription(),
secondComponent == null || !(secondComponent instanceof Accessible) ? null : secondComponent.getAccessibleContext().getAccessibleDescription()}));
}
///////////////////
// Inner Classes //
///////////////////
/** A listener interface for tracking split point changes */
public static interface SplitChangeListener {
/** Called when a split point changes
* @param evt The SplitChangeEvent that describes the change
*/
public void splitChanged (SplitChangeEvent evt);
}
/** An event that describes a split point change */
public static class SplitChangeEvent extends java.util.EventObject{
/** generated Serialized Version UID */
static final long serialVersionUID = 6748966611210836878L;
private int oldValue, newValue;
/** Constructs a new SplitChangeEvent for specified source SplittedPanel and
* old and new SplitPositions
*/
public SplitChangeEvent (SplittedPanel splittedPanel, int oldValue, int newValue) {
super(splittedPanel);
this.oldValue = oldValue;
this.newValue = newValue;
}
/** @return the old splitterPosition */
public int getOldValue() {
return oldValue;
}
/** @return the new splitterPosition */
public int getNewValue() {
return newValue;
}
}
/** The EmptySplitter is an empty splitter component with specified width.
* It can be used as the splitter via setSplitterComponent.
*/
public static class EmptySplitter extends JComponent implements Accessible {
/** generated Serialized Version UID */
static final long serialVersionUID = 929648193440460693L;
private int width;
private AccessibleContext accessibleContext;
public EmptySplitter () {
this (0);
}
public EmptySplitter (int width) {
ResourceBundle bundle = NbBundle.getBundle(SplittedPanel.class);
accessibleContext = null;
this.width = width;
getAccessibleContext().setAccessibleName(bundle.getString("ACS_SplittedPanel_EmptySplitter"));
getAccessibleContext().setAccessibleName(bundle.getString("ACSD_SplittedPanel_EmptySplitter"));
}
public Dimension getPreferredSize() {
return new Dimension (width, width);
}
public AccessibleContext getAccessibleContext () {
if(accessibleContext == null) {
accessibleContext = new AccessibleJComponent() {
public AccessibleRole getAccessibleRole() {
return AccessibleRole.SPLIT_PANE;
}
};
}
return accessibleContext;
}
}
/** The DefaultSplitter class implements a splitting line that is to be used as a default splitter for the SplittedPanel.
* It paints a raised 3D-line with given width.
*/
class DefaultSplitter extends JComponent implements Accessible {
private int splitterSize;
static final long serialVersionUID =-4223135481223014719L;
/**
* Constructs a new DefaultSplitter with given width.
* @param aWidth the desired width of the splitting line, if the value is lower than 2, the width of 2 is used
*/
public DefaultSplitter(int aSplitterSize) {
splitterSize = aSplitterSize;
if (splitterSize < 2) splitterSize = 2;
}
public Dimension getPreferredSize() {
return new Dimension (splitterSize, splitterSize);
}
public void paint(Graphics g) {
super.paint(g);
if (splitterSize <= 2) return;
Dimension size = this.getSize ();
int height = size.height-1;
g.setColor (this.getBackground ());
Color high=UIManager.getColor("controlLtHighlight");
//Color bg=UIManager.getColor("control");
Color low=UIManager.getColor("controlDkShadow");
boolean isMetal = UIManager.getLookAndFeel().getClass() ==
javax.swing.plaf.metal.MetalLookAndFeel.class;
boolean firstHasBorder = true;
boolean secondHasBorder = true;
if (firstComponent instanceof JComponent) {
Border b1 = ((JComponent) firstComponent).getBorder();
firstHasBorder = (b1 != null) && (!(b1 instanceof EmptyBorder));
}
if (secondComponent instanceof JComponent) {
Border b2 = ((JComponent) secondComponent).getBorder();
secondHasBorder = (b2 != null) && (!(b2 instanceof EmptyBorder));
}
if (panesSwapped) {
boolean b = firstHasBorder;
firstHasBorder = secondHasBorder;
secondHasBorder = b;
}
//draw the bumps
if (isMetal && splitterSize > 3 && drawBumps) {
//looks backwards, but isn't - splitType==vertical gives you a
//horizontal splitter
int starty = firstHasBorder && (splitType == VERTICAL) ? 0:2;
int startx = firstHasBorder && (splitType == HORIZONTAL) ? 0:2;
for (int x = startx; x+1 < size.width; x+=4) {
for (int y = starty; y+1 < height; y+=4) {
g.setColor (this.getBackground ().brighter ());
g.drawLine (x, y, x, y);
if (x < size.width && y < height)
g.drawLine (x+2, y+2, x+2, y+2);
g.setColor (this.getBackground ().darker ().darker ());
g.drawLine (x+1, y+1, x+1, y+1);
if (x < size.width && y < height)
g.drawLine (x+3, y+3, x+3, y+3);
}
}
}
if (splitType == HORIZONTAL) {
int pos = (size.width-splitterSize) / 2;
if (!firstHasBorder) {
g.setColor(isMetal ? low : high);
g.drawLine(pos, 0, pos, size.height - 1);
if (isMetal) {
g.setColor (high);
g.drawLine (pos+1, 0, pos+1, size.height -1);
}
}
if (!secondHasBorder) {
g.setColor(isMetal ? high : low);
g.drawLine(pos + splitterSize - 1, 0, pos + splitterSize - 1, size.height - 1);
if (isMetal) {
g.setColor (low);
g.drawLine(pos + splitterSize - 2, 0, pos + splitterSize - 2, size.height - 1);
}
}
} else if (splitType == VERTICAL) {
int pos = (size.height-splitterSize) / 2;
if (!firstHasBorder) {
g.setColor(isMetal ? low : high);
g.drawLine(0, pos, size.width - 1, pos);
if (isMetal) {
g.setColor (high);
g.drawLine (0, pos + 1, size.width-1, pos+1);
}
}
if (!secondHasBorder) {
g.setColor(isMetal ? high : low);
g.drawLine(0, pos + splitterSize - 1, size.width - 1, pos + splitterSize - 1);
if (isMetal) {
g.setColor (low);
g.drawLine(0, pos + splitterSize - 2, size.width - 1, pos + splitterSize - 2);
}
}
}
}
public AccessibleContext getAccessibleContext () {
return SplittedPanel.this.getAccessibleContext();
}
}
/**
* The MouseListenerAdapter class implements the dragging behaviour of the splitter.
*/
class MouseListenerAdapter extends MouseUtils.PopupMouseAdapter implements MouseListener,
MouseMotionListener, SplitChangeListener {
/** Called when the sequnce of mouse events should lead to actual
* showing of the popup menu.
* Should be redefined to show the menu.
* param evt The mouse release event - should be used to obtain the
* position of the popup menu
*/
protected void showPopup(MouseEvent e) {
updatePopupMenu();
if (isPopupMenuEnabled ())
popupMenu.show(splitter, e.getX(), e.getY());
}
/** A method implemented from the MouseListener interface to handle the splitter dragging */
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (continuousLayout == false) {
if (dragPos == -1) return;
if (!absolute) {
Dimension d = getSize();
if (splitType == VERTICAL)
dragPos = (100 * dragPos)/d.height;
else
dragPos = (100 * dragPos)/d.width;
}
setSplitPosition(dragPos);
dragPos = -1;
}
}
/** A method implemented from the MouseMotionListener interface to handle the splitter dragging */
public void mouseDragged(MouseEvent e) {
if (continuousLayout == true) {
Dimension d = getSize();
Point splitterPos = splitter.getLocation();
e.translatePoint(splitterPos.x, splitterPos.y);
if (splitType == VERTICAL) {
dragPos = e.getY();
if (dragPos > d.height) dragPos = d.height;
}
else {
dragPos = e.getX();
if (dragPos > d.width) dragPos = d.width;
}
if (dragPos < 0) dragPos = 0;
if (continuousLayout) {
if (dragPos == -1) return;
int newDragPos = dragPos;
if (!absolute) {
if (splitType == VERTICAL)
newDragPos = (100 * dragPos)/d.height;
else
newDragPos = (100 * dragPos)/d.width;
}
setSplitPosition(newDragPos);
}
}
}
/** A method implemented from the MouseMotionListener interface to handle the splitter dragging */
public void mouseMoved(MouseEvent e) {
}
/* Double click on the splitter re-sets the splitter to follow one of the fields */
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if (e.getClickCount() == 2 && isPopupMenuEnabled ()) {
resetSplitter ();
}
}
public void splitChanged (SplitChangeEvent evt) {
if (evt.getNewValue() == FIRST_PREFERRED || evt.getNewValue() == SECOND_PREFERRED) {
resetPosition = evt.getNewValue();
if (splitterCMI!=null)
splitterCMI.setEnabled (true);
}
}
}
/**
* The SplitLayout class implements a LayoutManager for the SplittedPanel.
*/
class SplitLayout extends Object implements LayoutManager2, java.io.Serializable {
static final long serialVersionUID =2034500275182524789L;
public void addLayoutComponent (String name, Component comp) {
throw new IllegalArgumentException("You must use the add(Component, Object) method for adding"); // NOI18N
}
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints == ADD_SPLITTER) // adding a splitter
splitter = comp;
else if (constraints == ADD_FIRST) { // adding to the left/top
if ((firstComponent != null) && (secondComponent == null)) // if we altready have ... [PENDING]
secondComponent = firstComponent;
firstComponent = comp;
if ((secondComponent != null) && (splitType == NONE))
splitType = DEFAULT_SPLIT_TYPE;
}
else if (constraints == ADD_SECOND) {
if (firstComponent == null)
firstComponent = comp;
else {
secondComponent = comp;
if (splitType == NONE)
splitType = DEFAULT_SPLIT_TYPE;
}
}
else throw new IllegalArgumentException("You must use one of the SplittedPanel.ADD_XXX constraints Objects"); // NOI18N
initAccessible();
}
public void removeLayoutComponent (Component comp) {
if (comp.equals(secondComponent))
secondComponent = null;
else if (comp.equals(firstComponent)) {
firstComponent = null;
if (secondComponent != null) {
firstComponent = secondComponent;
secondComponent = null;
}
}
initAccessible();
}
public Dimension preferredLayoutSize (Container parent) {
int width = 0;
int height = 0;
if (firstComponent != null) {
Dimension d = firstComponent.getPreferredSize();
width = d.width;
height = d.height;
}
if (secondComponent != null) {
Dimension d = secondComponent.getPreferredSize();
if (splitType == VERTICAL) {
int splitterSize = splitter.getPreferredSize ().height;
if (width < d.width) width = d.width;
height += splitterSize + d.height;
}
else {
int splitterSize = splitter.getPreferredSize ().width;
if (height < d.height) height = d.height;
width += splitterSize + d.width;
}
}
return new Dimension(width, height);
}
public Dimension minimumLayoutSize (Container parent) {
int width = 0;
int height = 0;
if (firstComponent != null) {
Dimension d = firstComponent.getMinimumSize();
width = d.width;
height = d.height;
}
if (secondComponent != null) {
Dimension d = secondComponent.getMinimumSize();
if (splitType == VERTICAL) {
int splitterSize = splitter.getMinimumSize ().height;
if (width < d.width) width = d.width;
height += splitterSize + d.height;
}
else {
int splitterSize = splitter.getMinimumSize ().width;
if (height < d.height) height = d.height;
width += splitterSize + d.width;
}
}
return new Dimension(width, height);
}
public void layoutContainer (Container parent) {
Dimension d = parent.getSize();
int sPosition = splitPosition;
// 1. first preferred
if (splitPosition == FIRST_PREFERRED) {
if (splitType == VERTICAL)
sPosition = firstComponent.getPreferredSize().height;
else
sPosition = firstComponent.getPreferredSize().width;
// 2. second preferred
} else if (splitPosition == SECOND_PREFERRED) {
if (splitType == VERTICAL) {
sPosition = d.height - splitter.getPreferredSize ().width - secondComponent.getPreferredSize().height;
} else {
sPosition = d.width - splitter.getPreferredSize ().height - secondComponent.getPreferredSize().width;
}
// 3. percent position
} else if (!absolute) {
int sp = splitPosition;
if (sp > 100) sp = 100;
if (splitType == VERTICAL)
sPosition = (d.height * sp) / 100;
else
sPosition = (d.width * sp) / 100;
}
if ((splitType != NONE) && (firstComponent != null) && (secondComponent != null)) { // splitted
if (splitType == VERTICAL) {
int splitterSize = splitter.getPreferredSize ().height;
if ((firstComponent == null) || (secondComponent==null)) {
splitterSize = 0;
}
if (keepSecondSame && !splitIsChanging) {
Dimension secondSize = secondComponent.getSize ();
if (secondSize.height != 0)
sPosition = d.height - secondSize.height - splitterSize;
}
if (sPosition + splitterSize > d.height)
sPosition = d.height - splitterSize;
if (sPosition < 0)
sPosition = 0;
firstComponent.setBounds(new Rectangle(0, 0, d.width, sPosition));
splitter.setBounds(new Rectangle(0, sPosition, d.width, splitterSize));
secondComponent.setBounds(new Rectangle(0, sPosition + splitterSize, d.width, d.height - sPosition - splitterSize));
}
else {
int splitterSize = splitter.getPreferredSize ().width;
if ((firstComponent == null) || (secondComponent==null)) {
splitterSize = 0;
}
if (keepSecondSame && !splitIsChanging) {
Dimension secondSize = secondComponent.getSize ();
if (secondSize.width != 0)
sPosition = d.width - secondSize.width - splitterSize;
}
if (sPosition + splitterSize > d.width)
sPosition = d.width - splitterSize;
if (sPosition < 0)
sPosition = 0;
firstComponent.setBounds(new Rectangle(0, 0, sPosition, d.height));
splitter.setBounds(new Rectangle(sPosition, 0, splitterSize, d.height));
secondComponent.setBounds(new Rectangle(sPosition + splitterSize, 0, d.width - sPosition - splitterSize, d.height));
}
}
else if (firstComponent != null) {
firstComponent.setBounds (new Rectangle(0, 0, d.width-1, d.height -1));
if (splitter != null)
splitter.setBounds (0, 0, 0, 0);
}
}
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
public float getLayoutAlignmentX(Container target) { return 0; }
public float getLayoutAlignmentY(Container target) { return 0; }
public void invalidateLayout(Container target) {}
}
/** Deserializes the component and initializes it. */
private void readObject(java.io.ObjectInputStream ois)
throws java.io.IOException, ClassNotFoundException {
ois.defaultReadObject();
init();
}
///////////////////////
// Private variables //
///////////////////////
/** the first (left/top) component */
private Component firstComponent = null;
/** the second (right/bottom) component */
private Component secondComponent = null;
/** the splitter component */
private Component splitter = null;
/** the splitter component type */
private int splitterType = DEFAULT_SPLITTER;
/** the mouse adapter that does the dragging of the splitter*/
private transient MouseListenerAdapter mouseAdapter;
/** current split type */
private int splitType = NONE;
/** current split position */
private int splitPosition = 50;
private boolean absolute = false;
private boolean dragable = true;
private boolean continuousLayout = true;
/** current enabled/disabled state of change of split type */
private boolean splitTypeChangeEnabled = true;
/** current enabled/disabled state of change of swapping panes */
private boolean swapPanesEnabled = true;
/** current keepSecondSame state - this has bigger priority than keepFirstSame */
private boolean keepSecondSame = false;
/** current keepFirstSame state */
private boolean keepFirstSame = false;
transient private boolean splitIsChanging = false;
private int dragPos = -1;
/** true if the panes were swapped, false otherwise */
private boolean panesSwapped = false;
/** The default split type */
private final static int DEFAULT_SPLIT_TYPE = HORIZONTAL;
/** popup menu for setting vertical/horizontal splitting */
transient private JPopupMenu popupMenu;
/** The popup menu item */
transient private JRadioButtonMenuItem verticalCMI;
/** The popup menu item */
transient private JRadioButtonMenuItem horizontalCMI;
/** The popup menu item */
transient private JMenuItem swapCMI;
/** The popup menu item */
transient private JMenuItem splitterCMI;
/** A Vector of SplitChangeListeners */
transient private Vector listeners;
/** Accessible context */
private AccessibleContext accessibleContext;
}