package org.geogebra.desktop.gui.layout;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JSplitPane;
import javax.swing.plaf.SplitPaneUI;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import org.geogebra.common.gui.layout.DockComponent;
import org.geogebra.common.io.layout.DockSplitPaneData;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.desktop.main.AppD;
/**
* Split pane which is used to separate two DockPanels.
*
* @author Florian Sonner
*/
public class DockSplitPane extends JSplitPane implements DockComponent {
private static final long serialVersionUID = 1L;
private boolean dividerVisible;
/**
* new split pane
*/
public DockSplitPane() {
this(JSplitPane.HORIZONTAL_SPLIT);
this.addPropertyChangeListener(paneResizeListener);
}
/**
* @param newOrientation
* orientation
*/
public DockSplitPane(int newOrientation) {
super(newOrientation);
// setResizeWeight(0.5);
setBorder(BorderFactory.createEmptyBorder());
dividerVisible = false;
this.addPropertyChangeListener(paneResizeListener);
}
/**
* Listener for split pane resizing. Transfers focus to the split pane after
* a resize event, thus removing focus and sending a focus lost event to the
* DockSplitPane components.
*/
PropertyChangeListener paneResizeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent changeEvent) {
JSplitPane splitPane = (JSplitPane) changeEvent.getSource();
String propertyName = changeEvent.getPropertyName();
if (propertyName
.equals(JSplitPane.LAST_DIVIDER_LOCATION_PROPERTY)) {
splitPane.requestFocus();
}
}
};
/**
* Return the component which is opposite to the parameter.
*
* @param component
* part of layout
* @return oposite component
*/
public Component getOpposite(Component component) {
if (component == leftComponent) {
return rightComponent;
} else if (component == rightComponent) {
return leftComponent;
} else {
throw new IllegalArgumentException();
}
}
/**
* set the left component and check if it's empty when loading file
*
* @param component
* componenent
*/
public void setLeftComponentCheckEmpty(Component component) {
// ensure visibility flags of dock panels set to false
if (leftComponent != null) {
((DockComponent) leftComponent).setDockPanelsVisible(false);
}
setLeftComponent(component);
}
/**
* set the left component and check if it's empty when loading file
*
* @param component
* componenent
*/
public void setRightComponentCheckEmpty(Component component) {
// ensure visibility flags of dock panels set to false
if (rightComponent != null) {
((DockComponent) rightComponent).setDockPanelsVisible(false);
}
setRightComponent(component);
}
/**
* Set the left component of this DockSplitPane and remove the divider if
* the left component is null.
*/
@Override
public void setLeftComponent(Component component) {
super.setLeftComponent(component);
updateDivider();
}
/**
* Set the right component of this DockSplitPane and remove the divider if
* the right component is null.
*/
@Override
public void setRightComponent(Component component) {
super.setRightComponent(component);
updateDivider();
}
/**
* Replace a component from the split pane with another.
*
* @param component
* part of layout
* @param replacement
* replacement
*/
public void replaceComponent(Component component, Component replacement) {
if (component == leftComponent) {
setLeftComponent(replacement);
} else if (component == rightComponent) {
setRightComponent(replacement);
} else {
throw new IllegalArgumentException();
}
}
/**
* Update the visibility of the divider.
*/
private void updateDivider() {
if (leftComponent == null || rightComponent == null) {
dividerVisible = false;
} else {
dividerVisible = true;
}
}
/**
* Update the UI by drawing the divider just if the dividerVisible attribute
* is set to true.
*/
@Override
public void updateUI() {
super.updateUI();
SplitPaneUI splitPaneUI = getUI();
if (splitPaneUI instanceof BasicSplitPaneUI) {
BasicSplitPaneUI basicUI = (BasicSplitPaneUI) splitPaneUI;
basicUI.getDivider().setVisible(dividerVisible);
}
}
/**
* A helper class used to get the split pane information array of the
* current layout. Use {@link #getInfo(DockSplitPane)} with the root pane as
* parameter to get the array.
*
* @author Florian Sonner
* @version 2008-10-26
*/
public static class TreeReader {
private AppD app;
private ArrayList<DockSplitPaneData> splitPaneInfo;
private int windowWidth;
private int windowHeight;
/**
* @param app
* application
*/
public TreeReader(AppD app) {
this.app = app;
splitPaneInfo = new ArrayList<DockSplitPaneData>();
}
/**
* @param rootPane
* layout root
* @return layout description
*/
public DockSplitPaneData[] getInfo(DockSplitPane rootPane) {
splitPaneInfo.clear();
if (app.isApplet()) {
windowWidth = app.getApplet().width;
} else {
windowWidth = app.getFrame().getWidth();
}
if (app.isApplet()) {
windowHeight = app.getApplet().height;
} else {
windowHeight = app.getFrame().getHeight();
}
saveSplitPane("", rootPane);
DockSplitPaneData[] info = new DockSplitPaneData[splitPaneInfo
.size()];
return splitPaneInfo.toArray(info);
}
/**
* Save a split pane into the splitPaneInfo array list
*
* @param parentLocation
* @param parent
*/
private void saveSplitPane(String parentLocation0,
DockSplitPane parent) {
double dividerLocation = 0.2;
String parentLocation = parentLocation0;
// get relative divider location depending on the current
// orientation
if (parent.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
dividerLocation = (double) parent.getDividerLocation()
/ windowWidth;
} else {
dividerLocation = (double) parent.getDividerLocation()
/ windowHeight;
}
splitPaneInfo.add(new DockSplitPaneData(parentLocation,
dividerLocation, parent.getOrientation()));
if (parentLocation.length() > 0) {
parentLocation += ",";
}
if (parent.getLeftComponent() instanceof DockSplitPane) {
saveSplitPane(parentLocation + "0",
(DockSplitPane) parent.getLeftComponent());
}
if (parent.getRightComponent() instanceof DockSplitPane) {
saveSplitPane(parentLocation + "1",
(DockSplitPane) parent.getRightComponent());
}
}
}
private int savedDividerLocation;
private int savedSize;
@Override
public void saveDividerLocation() {
if (getOrientation() == JSplitPane.VERTICAL_SPLIT) {
if (getLeftComponent() != null) {
savedDividerLocation = getLeftComponent().getHeight();
}
savedSize = getHeight();
} else {
if (getLeftComponent() != null) {
savedDividerLocation = getLeftComponent().getWidth();
}
savedSize = getWidth();
}
if (getLeftComponent() != null) {
((DockComponent) getLeftComponent()).saveDividerLocation();
}
if (getRightComponent() != null) {
((DockComponent) getRightComponent()).saveDividerLocation();
}
}
@Override
public void updateDividerLocation(int size, int orientation1) {
/*
* AbstractApplication.debug("\nresizeW= "+getResizeWeight() +"\nsize= "
* +size +"\nsavedSize= "+savedSize +"\nsavedDividerLocation= "
* +savedDividerLocation +"\nleft= "+getLeftComponent() +"\nright= "
* +getRightComponent());
*/
if (orientation1 == getOrientation()) {
if (getResizeWeight() == 0) {
setDividerLocationRecursive(
checkLocation(savedDividerLocation, size), size,
orientation1);
} else if (Kernel.isEqual(getResizeWeight(), 0.5)) {
if (savedSize == 0) {
savedSize = 1;
}
setDividerLocationRecursive(
(size * savedDividerLocation) / savedSize, size,
orientation1);
} else {
setDividerLocationRecursive(size
- checkLocation(savedSize - savedDividerLocation, size),
size, orientation1);
}
} else {
propagateDividerLocation(size, size, orientation1);
}
}
private static int checkLocation(int location, int size) {
int min = MIN_SIZE;
if (min > size / 2) {
min = size / 2;
}
if (location < min) {
return min;
}
if (location > size - min) {
return size - min;
}
return location;
}
private void setDividerLocationRecursive(int location, int size,
int orientation1) {
setDividerLocation(location);
// AbstractApplication.debug("location = "+location);
propagateDividerLocation(location, size - location, orientation1);
}
private void propagateDividerLocation(int sizeLeft, int sizeRight,
int orientation1) {
if (getLeftComponent() != null) {
((DockComponent) getLeftComponent()).updateDividerLocation(sizeLeft,
orientation1);
}
if (getRightComponent() != null) {
((DockComponent) getRightComponent())
.updateDividerLocation(sizeRight, orientation1);
}
}
@Override
public String toString(String prefix) {
String prefix2 = prefix + "-";
return "\n" + prefix + "split=" + getDividerLocation() + "\n" + prefix
+ "width=" + getWidth() + "\n" + prefix + "left"
+ ((DockComponent) getLeftComponent()).toString(prefix2) + "\n"
+ prefix + "right"
+ ((DockComponent) getRightComponent()).toString(prefix2);
}
@Override
public boolean updateResizeWeight() {
boolean takesNewSpaceLeft = false;
boolean takesNewSpaceRight = false;
if ((getLeftComponent() != null)
&& ((DockComponent) getLeftComponent()).updateResizeWeight()) {
takesNewSpaceLeft = true;
}
if ((getRightComponent() != null)
&& ((DockComponent) getRightComponent()).updateResizeWeight()) {
takesNewSpaceRight = true;
}
if (takesNewSpaceLeft) {
if (takesNewSpaceRight) {
setResizeWeight(0.5);
} else {
setResizeWeight(1);
}
return true;
} else if (takesNewSpaceRight) {
setResizeWeight(0);
return true;
}
setResizeWeight(0);
return false;
}
@Override
public void setDockPanelsVisible(boolean visible) {
if (leftComponent != null) {
((DockComponent) leftComponent).setDockPanelsVisible(visible);
}
if (rightComponent != null) {
((DockComponent) rightComponent).setDockPanelsVisible(visible);
}
}
}