package org.geogebra.web.web.gui.layout;
import java.util.ArrayList;
import org.geogebra.common.gui.layout.DockComponent;
import org.geogebra.common.io.layout.DockSplitPaneData;
import org.geogebra.common.javax.swing.SwingConstants;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.web.html5.main.AppW;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.Widget;
/**
* Split pane which is used to separate two DockPanels.
*
* @author Florian Sonner, adapted by G.Sturr for web
*/
public class DockSplitPaneW extends ZoomSplitLayoutPanel implements DockComponent {
private Widget leftComponent;
private Widget rightComponent;
private int orientation;
private int savedDividerLocation;
private int savedSize;
private double resizeWeight;
private int dividerLocation;
private AppW app;
/**
* For calling the onResize method in a deferred way
*/
Scheduler.ScheduledCommand deferredOnRes = new Scheduler.ScheduledCommand() {
@Override
public void execute() {
onResize();
}
};
private boolean forcedLayout = false;
private int preferredWidth;
private int preferredHeight;
/**
* For calling the onResize method in a deferred way
*/
public void deferredOnResize() {
Scheduler.get().scheduleDeferred(deferredOnRes);
}
/* other option; maybe not so good...
public void deferredOnResize() {
for (Widget c : getChildren()) {
if (c instanceof DockSplitPaneW) {
((DockSplitPaneW)c).deferredOnResize();
} else if (c instanceof DockPanelW) {
((DockPanelW)c).deferredOnResize();
} else if (c instanceof RequiresResize) {
((RequiresResize)c).onResize();
}
}
}*/
/*********************************************
* Constructs a DockSplitPaneW with default horizontal orientation
*/
public DockSplitPaneW(AppW app) {
this(SwingConstants.HORIZONTAL_SPLIT, app);
}
/*********************************************
* Constructs a DockSplitPaneW with given orientation
*
* @param newOrientation
*/
public DockSplitPaneW(int newOrientation, AppW app) {
super(1 / app.getArticleElement().getScaleX());
this.app = app;
setOrientation(newOrientation);
setResizeWeight(0.5);
// this.addPropertyChangeListener(paneResizeListener);
dividerLocation = 100;
}
// ========================================
// Getters/Setters
// ========================================
public int getDividerLocation() {
return dividerLocation;
}
public void setResizeWeight(double d) {
resizeWeight = d;
}
@Override
public boolean hasSplittersFrozen() {
return app.isApplet() && !app.isRightClickEnabled() && !app
.showMenuBar();
}
public double computeDividerLocationRecursive() {
double sizeLeft = 0;
if (getLeftComponent() instanceof DockSplitPaneW) {
sizeLeft = ((DockSplitPaneW)getLeftComponent()).computeSizeRecursive(orientation);
} else if (getLeftComponent() instanceof DockPanelW) {
sizeLeft = ((DockPanelW)getLeftComponent()).getEmbeddedSize();
}
double sizeAll = computeSizeRecursive(orientation);
if (sizeAll <= 0) {
return 0;
}
if (sizeLeft < 0) {
// well, why not return with 0?
return 0;
} else if (sizeLeft > sizeAll) {
// well, why not return with 1?
return 1;
}
return sizeLeft / sizeAll;
}
public double computeSizeRecursive(int parentOrientation) {
double size = 0;
if (orientation == parentOrientation) {
if (getLeftComponent() instanceof DockSplitPaneW) {
size += ((DockSplitPaneW)getLeftComponent()).computeSizeRecursive(orientation);
} else if (getLeftComponent() instanceof DockPanelW) {
size += ((DockPanelW)getLeftComponent()).getEmbeddedSize();
}
if (getRightComponent() instanceof DockSplitPaneW) {
size += ((DockSplitPaneW)getRightComponent()).computeSizeRecursive(orientation);
} else if (getRightComponent() instanceof DockPanelW) {
size += ((DockPanelW)getRightComponent()).getEmbeddedSize();
}
return size;
}
double size2 = 0;
if (getLeftComponent() instanceof DockSplitPaneW) {
size = ((DockSplitPaneW)getLeftComponent()).computeSizeRecursive(parentOrientation);
} else if (getLeftComponent() instanceof DockPanelW) {
// if orientation is different, use settings instead of embeddedSize
if (parentOrientation == SwingConstants.VERTICAL_SPLIT) {
size = ((DockPanelW)getLeftComponent()).getEstimatedSize().getHeight();
} else {
size = ((DockPanelW)getLeftComponent()).getEstimatedSize().getWidth();
}
}
if (getRightComponent() instanceof DockSplitPaneW) {
size2 = ((DockSplitPaneW)getRightComponent()).computeSizeRecursive(parentOrientation);
} else if (getRightComponent() instanceof DockPanelW) {
// if orientation is different, use settings instead of embeddedSize
if (parentOrientation == SwingConstants.VERTICAL_SPLIT) {
size2 = ((DockPanelW)getRightComponent()).getEstimatedSize().getHeight();
} else {
size2 = ((DockPanelW)getRightComponent()).getEstimatedSize().getWidth();
}
}
return Math.max(size, size2);
}
public void setDividerLocation(int location) {
setDividerLocationSilent(location);
setComponents();
}
public void setDividerLocationSilent(int location) {
dividerLocation = location;
}
public void setDividerLocation(double proportion) {
if (getOrientation() == SwingConstants.VERTICAL_SPLIT) {
setDividerLocation((int) (proportion * getOffsetHeight()));
} else {
setDividerLocation((int) (proportion * getOffsetWidth()));
}
}
public Widget getRightComponent() {
return rightComponent;
}
public Widget getLeftComponent() {
return leftComponent;
}
public int getOrientation() {
return orientation;
}
public void setOrientation(int newOrientation) {
orientation = newOrientation;
}
public double getResizeWeight() {
return resizeWeight;
}
/**
* Return the component which is opposite to the parameter.
*
* @param component
* @return
*/
public Widget getOpposite(Widget 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(Widget component) {
// ensure visibility flags of dock panels set to false
if (leftComponent != null) {
((DockComponent) leftComponent).setDockPanelsVisible(false);
}
setLeftComponent(component);
}
/**
* set the right component and check if it's empty when loading file
*
* @param component
* componenent
*/
public void setRightComponentCheckEmpty(Widget 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.
*/
public void setLeftComponent(Widget component) {
leftComponent = component;
setComponents();
}
/**
* Set the right component of this DockSplitPane and remove the divider if
* the right component is null.
*/
public void setRightComponent(Widget component) {
rightComponent = component;
setComponents();
}
public void setComponentsSilent() {
// if both components exist give the resizing pane to rightComponent
// (in Swing this corresponds to resize weight = 1)
if (leftComponent != null && rightComponent != null) {
if (orientation == SwingConstants.HORIZONTAL_SPLIT) {
addWest(leftComponent, dividerLocation);
add(rightComponent);
} else {
addNorth(leftComponent, dividerLocation);
add(rightComponent);
}
}
// otherwise put the single component into the resizing pane
else if (leftComponent != null) {
if (orientation == SwingConstants.HORIZONTAL_SPLIT) {
add(leftComponent);
} else {
add(leftComponent);
}
}
else if (rightComponent != null) {
add(rightComponent);
}
// forceLayout();
}
private void setComponents() {
clear();
setComponentsSilent();
}
public void setComponentsSilentRecursive() {
setComponentsSilent();
updateUI();
forceLayout();
if (getLeftComponent() instanceof DockSplitPaneW) {
((DockSplitPaneW)getLeftComponent()).setComponentsSilentRecursive();
} /*else if (getLeftComponent() instanceof DockPanelW) {
((DockPanelW)getLeftComponent()).updatePanel();
}*/
if (getRightComponent() instanceof DockSplitPaneW) {
((DockSplitPaneW)getRightComponent()).setComponentsSilentRecursive();
} /*else if (getRightComponent() instanceof DockPanelW) {
((DockPanelW)getRightComponent()).updatePanel();
}*/
}
/**
* Replace a component from the split pane with another.
*
* @param component
* @param replacement
*/
public void replaceComponent(Widget component, Widget replacement) {
if (component == leftComponent) {
setLeftComponent(replacement);
} else if (component == rightComponent) {
setRightComponent(replacement);
} else {
throw new IllegalArgumentException();
}
}
/**
* Update the UI by drawing the divider just if the dividerVisible attribute
* is set to true.
*/
public void updateUI() {
// super.updateUI();
// SplitPaneUI splitPaneUI = getUI();
// if (splitPaneUI instanceof BasicSplitPaneUI) {
// BasicSplitPaneUI basicUI = (BasicSplitPaneUI) splitPaneUI;
// basicUI.getDivider().setVisible(dividerVisible);
// }
}
@Override
public void saveDividerLocation() {
if (getOrientation() == SwingConstants.VERTICAL_SPLIT) {
if (getLeftComponent() != null) {
savedDividerLocation = getLeftComponent().getOffsetHeight();
}
savedSize = getOffsetHeight();
} else {
if (getLeftComponent() != null) {
savedDividerLocation = getLeftComponent().getOffsetWidth();
}
savedSize = getOffsetWidth();
}
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=" + getOffsetWidth() + "\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);
}
}
/*************************************************************************
* A helper class used to get the split pane information array of the
* current layout. Use {@link #getInfo(DockSplitPaneW)} with the root pane
* as parameter to get the array.
*
* @author Florian Sonner
* @version 2008-10-26
*/
public static class TreeReader {
private AppW app;
private ArrayList<DockSplitPaneData> splitPaneInfo;
private int windowWidth;
private int windowHeight;
public TreeReader(AppW app) {
this.app = app;
splitPaneInfo = new ArrayList<DockSplitPaneData>();
}
public DockSplitPaneData[] getInfo(DockSplitPaneW rootPane) {
splitPaneInfo.clear();
// get window dimensions
// TODO: Are these the correct dimensions needed for calculations below?
// e.g. do we include menubar height?
windowWidth = (int) app.getWidth();
windowHeight = (int) app.getHeight();
saveSplitPane("", rootPane);
DockSplitPaneData[] info = new DockSplitPaneData[splitPaneInfo
.size()];
return splitPaneInfo.toArray(info);
}
/**
* Save a split pane into the splitPaneInfo array list
*
* @param parentLocation0
* @param parent
*/
private void saveSplitPane(String parentLocation0,
DockSplitPaneW parent) {
double dividerLocation = 0.2;
// get relative divider location depending on the current
// orientation
if (parent.getOrientation() == SwingConstants.HORIZONTAL_SPLIT) {
dividerLocation = (double) parent.getDividerLocation()
/ windowWidth;
} else {
dividerLocation = (double) parent.getDividerLocation()
/ windowHeight;
}
splitPaneInfo.add(new DockSplitPaneData(parentLocation0,
dividerLocation, parent.getOrientation()));
String parentLocation = parentLocation0;
if (parentLocation.length() > 0) {
parentLocation += ",";
}
if (parent.getLeftComponent() instanceof DockSplitPaneW) {
saveSplitPane(parentLocation + "0",
(DockSplitPaneW) parent.getLeftComponent());
}
if (parent.getRightComponent() instanceof DockSplitPaneW) {
saveSplitPane(parentLocation + "1",
(DockSplitPaneW) parent.getRightComponent());
}
}
}
@Override
public void onResize() {
if (this.getWidgetCount() > 0) {
// If the split pane gets really narrow and right view is hidden,
if (orientation == SwingConstants.HORIZONTAL_SPLIT
&& getOffsetWidth() > 0
&& getOffsetWidth() < this.getWidget(0).getOffsetWidth()) {
this.setWidgetSize(this.getWidget(0), this.getOffsetWidth());
}
else if (orientation == SwingConstants.VERTICAL_SPLIT
&& getOffsetHeight() > 0
&& getOffsetHeight() < this.getWidget(0).getOffsetHeight()) {
this.setWidgetSize(this.getWidget(0), this.getOffsetHeight());
}
}
// it's only important to resize components so that
// the divider should be inside
if (getLeftComponent() instanceof RequiresResize) {
((RequiresResize)getLeftComponent()).onResize();
}
if (getRightComponent() instanceof DockSplitPaneW) {
((RequiresResize)getRightComponent()).onResize();
((DockSplitPaneW)getRightComponent()).checkDividerIsOutside();
} else if (getRightComponent() instanceof RequiresResize) {
((RequiresResize)getRightComponent()).onResize();
}
if (orientation == SwingConstants.HORIZONTAL_SPLIT) {
if (getLeftComponent() != null && getLeftComponent().getOffsetWidth() > 0) {
setDividerLocationSilent(getLeftComponent().getOffsetWidth());
}
} else {
if (getLeftComponent() != null && getLeftComponent().getOffsetHeight() > 0) {
setDividerLocationSilent(getLeftComponent().getOffsetHeight());
}
}
}
public void checkDividerIsOutside() {
// w, h should contain the dimensions visible on screen
int w = this.getElement().getClientWidth();
int h = this.getElement().getClientHeight();
if (orientation == SwingConstants.HORIZONTAL_SPLIT) {
if (getDividerLocation() >= w && (w > 0)) {
setDividerLocation(0.5);
}
} else {
if (getDividerLocation() >= h && (h > 0)) {
setDividerLocation(0.5);
}
}
}
@Override
public void forceLayout() {
setForcedLayout(true);
super.forceLayout();
setForcedLayout(false);
}
public boolean isForcedLayout() {
return forcedLayout;
}
public void setForcedLayout(boolean forcedLayout) {
this.forcedLayout = forcedLayout;
}
public boolean isCenter(Widget widget) {
LayoutData data = (LayoutData) widget.getLayoutData();
return data.direction == Direction.CENTER;
}
public int getPreferredHeight(DockPanelW dockPanelW) {
if (this.orientation == SwingConstants.HORIZONTAL_SPLIT) {
return preferredHeight;
}
return dockPanelW == getLeftComponent() ? this.dividerLocation
: preferredHeight - this.dividerLocation - getSplitterSize();
}
public int getPreferredWidth(DockPanelW dockPanelW) {
if (this.orientation == SwingConstants.VERTICAL_SPLIT) {
return preferredWidth;
}
return dockPanelW == getLeftComponent() ? this.dividerLocation
: preferredWidth - this.dividerLocation - getSplitterSize();
}
public void setPreferredWidth(int width, int height) {
this.preferredHeight = height;
this.preferredWidth = width;
}
public int getEstimateWidth() {
return getOffsetWidth() > 0 ? getOffsetWidth() : preferredWidth;
}
public int getEstimateHeight() {
return getOffsetHeight() > 0 ? getOffsetHeight() : preferredHeight;
}
}