/* * @(#)JideSplitPaneLayout.java 7/7/2009 * * Copyright 2002 - 2009 JIDE Software Inc. All rights reserved. * */ package com.jidesoft.swing; import com.jidesoft.utils.SystemInfo; import javax.swing.*; import java.awt.*; import java.util.*; /** * Layout manager used by JideSplitPane. */ public class JideSplitPaneLayout extends JideBoxLayout { private static final long serialVersionUID = -1826651835409198865L; public JideSplitPaneLayout(Container target) { super(target); setResetWhenInvalidate(false); } public JideSplitPaneLayout(Container target, int axis) { super(target, axis); setResetWhenInvalidate(false); } public JideSplitPaneLayout(Container target, int axis, int gap) { super(target, axis, gap); setResetWhenInvalidate(false); } int getDividerLocation(int index) { if (_componentSizes == null) { return -1; } if (index < 0 || (index + 1) << 1 >= _componentSizes.length) return -1; boolean ltr = _target.getComponentOrientation().isLeftToRight(); boolean reversed = !ltr && ((JideSplitPane) _target).getOrientation() == JideSplitPane.HORIZONTAL_SPLIT; int location = 0; if (reversed) { for (int i = _componentSizes.length - 1; i >= (index * 2) + 1; i--) location += _componentSizes[i]; } else { for (int i = 0; i < (index * 2) + 1; i++) location += _componentSizes[i]; } Insets insets = _target.getInsets(); if (insets != null) { if (((JideSplitPane) _target).getOrientation() == JideSplitPane.HORIZONTAL_SPLIT) { location += reversed ? insets.right : insets.left; } else { location += insets.top; } } return location; } @SuppressWarnings({"RedundantCast"}) int setDividerLocation(int index, int location, boolean isOriginator) { int oldLocation = getDividerLocation(index); if (oldLocation == -1 || oldLocation == location) return -1; boolean ltr = _target.getComponentOrientation().isLeftToRight(); boolean reversed = !ltr && ((JideSplitPane) _target).getOrientation() == JideSplitPane.HORIZONTAL_SPLIT; int prevIndex = reversed ? 2 * index + 2 : 2 * index; int nextIndex = reversed ? 2 * index : 2 * index + 2; int nextDividerIndex = reversed ? index - 1 : index + 1; int prevDividerIndex = reversed ? index + 1 : index - 1; int flexibleNextIndex; int flexiblePrevIndex; java.util.List<Integer> componentIndexChanged = new ArrayList<Integer>(); if (reversed) { while (nextIndex >= 0 && !isPaneVisible(nextIndex)) { nextIndex -= 2; nextDividerIndex --; } while (prevIndex < _componentSizes.length && !isPaneVisible(prevIndex)) { prevIndex += 2; prevDividerIndex ++; } flexibleNextIndex = nextIndex; while (flexibleNextIndex >= 0 && (getConstraintMap().get(_target.getComponent(flexibleNextIndex)) == JideBoxLayout.FIX || !isPaneVisible(flexibleNextIndex))) { flexibleNextIndex -= 2; } if (flexibleNextIndex < 0) { return -1; } flexiblePrevIndex = prevIndex; while (flexiblePrevIndex < _componentSizes.length && (getConstraintMap().get(_target.getComponent(flexiblePrevIndex)) == JideBoxLayout.FIX || !isPaneVisible(flexiblePrevIndex))) { flexiblePrevIndex += 2; } if (flexiblePrevIndex >= _componentSizes.length) { return -1; } } else { while (nextIndex < _componentSizes.length && !isPaneVisible(nextIndex)) { nextIndex += 2; nextDividerIndex ++; } while (prevIndex >= 0 && !isPaneVisible(prevIndex)) { prevIndex -= 2; prevDividerIndex --; } flexibleNextIndex = nextIndex; while (flexibleNextIndex < _componentSizes.length && (getConstraintMap().get(_target.getComponent(flexibleNextIndex)) == JideBoxLayout.FIX || !isPaneVisible(flexibleNextIndex))) { flexibleNextIndex += 2; } if (flexibleNextIndex >= _componentSizes.length) { return -1; } flexiblePrevIndex = prevIndex; while (flexiblePrevIndex >= 0 && (getConstraintMap().get(_target.getComponent(flexiblePrevIndex)) == JideBoxLayout.FIX || !isPaneVisible(flexiblePrevIndex))) { flexiblePrevIndex -= 2; } if (flexiblePrevIndex < 0) { return -1; } } if (isOriginator && getConstraintMap().get(_target.getComponent(nextIndex)) == JideBoxLayout.FIX && getConstraintMap().get(_target.getComponent(prevIndex)) == JideBoxLayout.FIX) { return -1; } if (location > oldLocation) { int size = _componentSizes[2 * index + 1]; if (getConstraintMap().get(_target.getComponent(nextIndex)) == JideBoxLayout.FIX) { size += _componentSizes[nextIndex]; } else { if (((JideSplitPane) _target).getOrientation() == JideSplitPane.HORIZONTAL_SPLIT) { size += _target.getComponent(nextIndex).getMinimumSize().getWidth(); } else { size += _target.getComponent(nextIndex).getMinimumSize().getHeight(); } } int nextDividerLocation = getDividerLocation(nextDividerIndex); if (nextDividerLocation < 0) { if (((JideSplitPane) _target).getOrientation() == JideSplitPane.HORIZONTAL_SPLIT) { location = Math.min(location, _target.getWidth() - size); } else { location = Math.min(location, _target.getHeight() - size); } } else if (location + size > nextDividerLocation) { int actualLocation = setDividerLocation(nextDividerIndex, location + size, false); if (actualLocation == -1) { return -1; } location = actualLocation - size; } if (getConstraintMap().get(_target.getComponent(nextIndex)) != JideBoxLayout.FIX) { _componentSizes[nextIndex] -= location - oldLocation; componentIndexChanged.add(nextIndex); } if (isOriginator) { _componentSizes[flexiblePrevIndex] += location - oldLocation; componentIndexChanged.add(flexiblePrevIndex); } else if (getConstraintMap().get(_target.getComponent(prevIndex)) != JideBoxLayout.FIX) { _componentSizes[prevIndex] += location - oldLocation; componentIndexChanged.add(prevIndex); } } else if (location < oldLocation) { int size = 0; if (prevDividerIndex >= 0) { size = _componentSizes[prevIndex - 1]; } if (getConstraintMap().get(_target.getComponent(prevIndex)) == JideBoxLayout.FIX) { size += _componentSizes[prevIndex]; } else { if (((JideSplitPane) _target).getOrientation() == JideSplitPane.HORIZONTAL_SPLIT) { size += _target.getComponent(prevIndex).getMinimumSize().getWidth(); } else { size += _target.getComponent(prevIndex).getMinimumSize().getHeight(); } } int prevDividerLocation = getDividerLocation(prevDividerIndex); if (prevDividerLocation < 0) { location = Math.max(location, size); } else if (location - size < prevDividerLocation) { int actualLocation = setDividerLocation(prevDividerIndex, location - size, false); if (actualLocation == -1) { return -1; } location = actualLocation + size; } if (getConstraintMap().get(_target.getComponent(prevIndex)) != JideBoxLayout.FIX) { _componentSizes[prevIndex] -= oldLocation - location; componentIndexChanged.add(prevIndex); } if (isOriginator) { _componentSizes[flexibleNextIndex] += oldLocation - location; componentIndexChanged.add(flexibleNextIndex); } else if (getConstraintMap().get(_target.getComponent(nextIndex)) != JideBoxLayout.FIX) { _componentSizes[nextIndex] += oldLocation - location; componentIndexChanged.add(nextIndex); } } if (SystemInfo.isJdk15Above()) { if (_target instanceof JideSplitPane) { ((JideSplitPane) _target).firePropertyChange(JideSplitPane.PROPERTY_DIVIDER_LOCATION, oldLocation, location); } else { _target.firePropertyChange(JideSplitPane.PROPERTY_DIVIDER_LOCATION, oldLocation, location); } } ((JideSplitPane) _target).revalidate(); if (((JideSplitPane) _target).isProportionalLayout()) { replaceProportions(); return location; } if (((JideSplitPane) _target).getOrientation() == JideSplitPane.HORIZONTAL_SPLIT) { for (int changedIndex = 0; changedIndex < _target.getComponentCount(); changedIndex++) { Component component = _target.getComponent(changedIndex); if (component instanceof JComponent && !(component instanceof JideSplitPaneDivider)) { ((JComponent) component).setPreferredSize(new Dimension(_componentSizes[changedIndex], component.getPreferredSize().height)); } } } else { for (int changedIndex = 0; changedIndex < _target.getComponentCount(); changedIndex++) { Component component = _target.getComponent(changedIndex); if (component instanceof JComponent && !(component instanceof JideSplitPaneDivider)) { ((JComponent) component).setPreferredSize(new Dimension(component.getPreferredSize().width, _componentSizes[changedIndex])); } } } return location; } private boolean isPaneVisible(int index) { // Considering collapse/expand feature, we need consider the visibility of divider as well return index < _componentSizes.length && (_componentSizes[index] != 0 || index - 1 < 0 || _componentSizes[index - 1] != 0); } /** * Uses the component sizes to generate a new array of proportions, and replaces the existing one. */ private void replaceProportions() { ((JideSplitPane) _target).setProportions(deduceProportions()); } /** * Uses the component sizes to generate a new array of proportions. * * @return a new array of proportions */ private double[] deduceProportions() { double total = 0.0; // Total height or width of contained panes (not including dividers) for (int i = 0; i < _componentSizes.length; i += 2) // Note we're skipping dividers total += _componentSizes[i]; double[] newProportions; if (total == 0.0) newProportions = null; else { newProportions = new double[(_componentSizes.length - 1) / 2]; for (int i = 0; i < newProportions.length; ++i) newProportions[i] = _componentSizes[i * 2] / total; } return newProportions; } // For proportional layouts, override the key box layout method: @Override protected boolean calculateComponentSizes(int availableSize, int startIndex, int endIndex) { // Just go to super for non-proportional layout, or if there are no more // than one component. if (!((JideSplitPane) _target).isProportionalLayout() || _target.getComponentCount() <= 1) return super.calculateComponentSizes(availableSize, startIndex, endIndex); // If we have no set proportions, either call super to get initial // proportions or set them up as even. if (((JideSplitPane) _target).getProportions() == null) { if (!((JideSplitPane) _target).isInitiallyEven()) { if (!super.calculateComponentSizes(availableSize, startIndex, endIndex)) return false; //<syd_0033> Luke's change // David: We now wait to set proportions until the user sets them directly. Otherwise recreated // docked frames end up with tiny sizes instead of using preferred size, since they are // initially added to their ContainerContainers without their contents. // _proportions = deduceProportions(); // Note no call to setProportions: no event //</syd_0033> return true; } // What remains is the "initially even" logic: int c = ((JideSplitPane) _target).getPaneCount(); double[] p = new double[c - 1]; for (int i = 0; i < p.length; ++i) p[i] = 1.0 / c; ((JideSplitPane) _target).internalSetProportions(p); // Note no call to setProportions: no event may be sent here } // Spin through the dividers, setting up their sizes and subtracting from available. for (int i = 1; i < _target.getComponentCount(); i += 2) { if (_target.getComponent(i).isVisible()) _componentSizes[i] = ((JideSplitPane) _target).getDividerSize(); availableSize -= _componentSizes[i]; } if (availableSize < 0) return false; // Then spin through the panes and set their sizes according to the // proportions. double[] proportions = ((JideSplitPane) _target).getProportions(); // double last = 1.0; // for (double p : proportions) last -= p; // double total = 0.0; // for (int i = 0; i < getComponentCount(); i += 2) { // int j = i / 2; // if (getComponent(i).isVisible()) // total += (j < proportions.length) ? proportions[j] : last; // } int size = availableSize; for (int i = 0; i < proportions.length; ++i) { int j = i * 2; if (_target.getComponent(j).isVisible()) { double d = proportions[i]/* / total*/; if (d <= 1.0) _componentSizes[j] = (int) (0.5 + size * d); } availableSize -= _componentSizes[j]; } // Now set the last one to whatever is left over. if (availableSize < 0) return false; _componentSizes[_componentSizes.length - 1] = availableSize; return true; } }