Package com.intellij.openapi.ui

Source Code of com.intellij.openapi.ui.Splitter$Divider

/*
* Copyright 2000-2007 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.ui;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.wm.FocusWatcher;
import com.intellij.ui.UIBundle;
import org.jetbrains.annotations.NonNls;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
* @author Vladimir Kondratyev
*/
public class Splitter extends JPanel {
  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.ui.Splitter");
  @NonNls public static final String PROP_PROPORTION = "proportion";

  private int myDividerWidth;
  /**
   * /------/
   * |  1   |
   * This is vertical split |------|
   * |  2   |
   * /------/
   * <p/>
   * /-------/
   * |   |   |
   * This is horihontal split | 1 | 2 |
   * |   |   |
   * /-------/
   */
  private boolean myVerticalSplit;
  private boolean myHonorMinimumSize = false;
  private final float myMinProp;
  private final float myMaxProp;


  private float myProportion;

  private final Divider myDivider;
  private JComponent mySecondComponent;
  private JComponent myFirstComponent;
  private final FocusWatcher myFocusWatcher;
  private boolean myShowDividerControls;


  /**
   * Creates horizontal split with proportion equals to .5f
   */
  public Splitter() {
    this(false);
  }

  /**
   * Creates split with specified orientation and proportion equals to .5f
   */
  public Splitter(boolean vertical) {
    this(vertical, .5f);
  }

  /**
   * Creates split with specified orientation and proportion.
   */
  public Splitter(boolean vertical, float proportion) {
    this(vertical, proportion, 0.0f, 1.0f);
  }

  public Splitter(boolean vertical, float proportion, float minProp, float maxProp) {
    myMinProp = minProp;
    myMaxProp = maxProp;
    LOG.assertTrue(minProp >= 0.0f);
    LOG.assertTrue(maxProp <= 1.0f);
    LOG.assertTrue(minProp <= maxProp);
    myVerticalSplit = vertical;
    myShowDividerControls = false;
    myDivider = createDivider();
    setProportion(proportion);
    myDividerWidth = 7;
    setOpaque(false);
    super.add(myDivider);
    myFocusWatcher = new FocusWatcher();
    myFocusWatcher.install(this);
  }

  public void setShowDividerControls(boolean showDividerControls) {
    myShowDividerControls = showDividerControls;
    setOrientation(myVerticalSplit);
  }

  public boolean isHonorMinimumSize() {
    return myHonorMinimumSize;
  }

  public void setHonorComponentsMinimumSize(boolean honorMinimumSize) {
    myHonorMinimumSize = honorMinimumSize;
  }

  /**
   * This is temporary solution for UIDesigner. <b>DO NOT</b> use it from code.
   *
   * @see #setFirstComponent(JComponent)
   * @see #setSecondComponent(JComponent)
   * @deprecated
   */
  public Component add(Component comp) {
    final int childCount = getComponentCount();
    LOG.assertTrue(childCount >= 1);
    if (childCount > 3) {
      throw new IllegalStateException("" + childCount);
    }
    LOG.assertTrue(childCount <= 3);
    if (childCount == 1) {
      setFirstComponent((JComponent)comp);
    }
    else {
      setSecondComponent((JComponent)comp);
    }
    return comp;
  }

  public void dispose() {
    myFocusWatcher.deinstall(this);
  }

  protected Divider createDivider() {
    return new Divider();
  }

  public boolean isVisible() {
    return super.isVisible() &&
           (myFirstComponent != null && myFirstComponent.isVisible() || mySecondComponent != null && mySecondComponent.isVisible());
  }

  public Dimension getMinimumSize() {
    final int dividerWidth = getDividerWidth();
    if (myFirstComponent != null && myFirstComponent.isVisible() && mySecondComponent != null && mySecondComponent.isVisible()) {
      final Dimension firstMinSize = myFirstComponent.getMinimumSize();
      final Dimension secondMinSize = mySecondComponent.getMinimumSize();
      return getOrientation()
             ? new Dimension(Math.max(firstMinSize.width, secondMinSize.width), firstMinSize.height + dividerWidth + secondMinSize.height)
             : new Dimension(firstMinSize.width + dividerWidth + secondMinSize.width, Math.max(firstMinSize.height, secondMinSize.height));
    }

    if (myFirstComponent != null && myFirstComponent.isVisible()) { // only first component is visible
      return myFirstComponent.getMinimumSize();
    }

    if (mySecondComponent != null && mySecondComponent.isVisible()) { // only second component is visible
      return mySecondComponent.getMinimumSize();
    }

    return super.getMinimumSize();
  }

  public void doLayout() {
    final int width = getWidth();
    final int height = getHeight();
    if (!isNull(myFirstComponent) && myFirstComponent.isVisible() && !isNull(mySecondComponent) && mySecondComponent.isVisible()) {
      // both first and second components are visible
      Rectangle firstRect = new Rectangle();
      Rectangle dividerRect = new Rectangle();
      Rectangle secondRect = new Rectangle();

      final int componentSize = getOrientation() ? height : width;
      int dividerWidth = getDividerWidth();
      int firstCompontSize;
      int secondComponentSize;

      if (componentSize <= dividerWidth) {
        firstCompontSize = 0;
        secondComponentSize = 0;
        dividerWidth = componentSize;
      }
      else {
        firstCompontSize = (int)(myProportion * (float)(componentSize - dividerWidth));
        secondComponentSize = getOrientation() ? height - firstCompontSize - dividerWidth : width - firstCompontSize - dividerWidth;

        if (isHonorMinimumSize()) {
          final int firstMinSize = getOrientation() ? myFirstComponent.getMinimumSize().height : myFirstComponent.getMinimumSize().width;
          final int secondMinSize = getOrientation() ? mySecondComponent.getMinimumSize().height : mySecondComponent.getMinimumSize().width;

          if (firstCompontSize + secondComponentSize <= firstMinSize + secondMinSize) {
            float propotion = firstMinSize / (firstMinSize + (float)secondMinSize);
            firstCompontSize = (int)(propotion * (float)(componentSize - dividerWidth));
            secondComponentSize = getOrientation() ? height - firstCompontSize - dividerWidth : width - firstCompontSize - dividerWidth;
          }
          else {
            if (firstCompontSize < firstMinSize) {
              if (secondComponentSize - (firstMinSize - firstCompontSize) > secondMinSize) {
                secondComponentSize = secondComponentSize - (firstMinSize - firstCompontSize);
              }
              firstCompontSize = firstMinSize;
            }
            else if (secondComponentSize < secondMinSize) {
              firstCompontSize = firstCompontSize - (secondMinSize - secondComponentSize);
              secondComponentSize = secondMinSize;
            }
          }
        }
      }

      if (getOrientation()) {
        firstRect.setBounds(0, 0, width, firstCompontSize);
        dividerRect.setBounds(0, firstCompontSize, width, dividerWidth);
        secondRect.setBounds(0, firstCompontSize + dividerWidth, width, secondComponentSize);
      }
      else {
        firstRect.setBounds(0, 0, firstCompontSize, height);
        dividerRect.setBounds(firstCompontSize, 0, dividerWidth, height);
        secondRect.setBounds(firstCompontSize + dividerWidth, 0, secondComponentSize, height);
      }
      myDivider.setVisible(true);
      myFirstComponent.setBounds(firstRect);
      myDivider.setBounds(dividerRect);
      mySecondComponent.setBounds(secondRect);
      myFirstComponent.validate();
      mySecondComponent.validate();
    }
    else if (!isNull(myFirstComponent) && myFirstComponent.isVisible()) { // only first component is visible
      hideNull(mySecondComponent);
      myDivider.setVisible(false);
      myFirstComponent.setBounds(0, 0, width, height);
      myFirstComponent.validate();
    }
    else if (!isNull(mySecondComponent) && mySecondComponent.isVisible()) { // only second component is visible
      hideNull(myFirstComponent);
      myDivider.setVisible(false);
      mySecondComponent.setBounds(0, 0, width, height);
      mySecondComponent.validate();
    }
    else { // both components are null or invisible
      myDivider.setVisible(false);
      if (myFirstComponent != null) {
        myFirstComponent.setBounds(0, 0, 0, 0);
        myFirstComponent.validate();
      } else {
        hideNull(myFirstComponent);
      }
      if (mySecondComponent != null) {
        mySecondComponent.setBounds(0, 0, 0, 0);
        mySecondComponent.validate();
      } else {
        hideNull(mySecondComponent);
      }
    }
    myDivider.doLayout();
  }

  static boolean isNull(Component component) {
    return NullableComponent.Check.isNull(component);
  }

  static void hideNull(Component component) {
    if (component instanceof NullableComponent) {
      component.setBounds(0, 0, 0, 0);
      component.validate();
    }
  }

  public int getDividerWidth() {
    return myDividerWidth;
  }

  public void setDividerWidth(int width) {
    if (width <= 0) {
      throw new IllegalArgumentException("Wrong divider width: " + width);
    }
    if (myDividerWidth != width) {
      myDividerWidth = width;
      doLayout();
      repaint();
    }
  }

  public float getProportion() {
    return myProportion;
  }

  public void setProportion(float proportion) {
    if (myProportion == proportion) {
      return;
    }
    if (proportion < .0f || proportion > 1.0f) {
      throw new IllegalArgumentException("Wrong proportion: " + proportion);
    }
    if (proportion < myMinProp) proportion = myMinProp;
    if (proportion > myMaxProp) proportion = myMaxProp;
    float oldProportion = myProportion;
    myProportion = proportion;
    firePropertyChange(PROP_PROPORTION, new Float(oldProportion), new Float(myProportion));
    doLayout();
    repaint();
  }

  /**
   * Swaps components.
   */
  public void swapComponents() {
    JComponent tmp = myFirstComponent;
    myFirstComponent = mySecondComponent;
    mySecondComponent = tmp;
    doLayout();
    repaint();
  }

  /**
   * @return <code>true</code> if splitter has vertical orientation, <code>false</code> otherwise
   */
  public boolean getOrientation() {
    return myVerticalSplit;
  }

  /**
   * @param verticalSplit <code>true</code> means that splitter will have vertical split
   */
  public void setOrientation(boolean verticalSplit) {
    myVerticalSplit = verticalSplit;
    myDivider.setOrientation(verticalSplit);
    doLayout();
    repaint();
  }

  public JComponent getFirstComponent() {
    return myFirstComponent;
  }

  /**
   * Sets component which is located as the "first" splitted area. The method doesn't validate and
   * repaint the splitter. If there is already
   *
   * @param component
   */
  public void setFirstComponent(JComponent component) {
    if (myFirstComponent != component) {
      if (myFirstComponent != null) {
        remove(myFirstComponent);
      }
      myFirstComponent = component;
      if (myFirstComponent != null) {
        super.add(myFirstComponent);
        myFirstComponent.invalidate();
      }
    }
  }

  public JComponent getSecondComponent() {
    return mySecondComponent;
  }

  public JComponent getOtherComponent(final Component comp) {
    if (comp.equals(getFirstComponent())) return getSecondComponent();
    if (comp.equals(getSecondComponent())) return getFirstComponent();
    LOG.error("invalid component");
    return getFirstComponent();
  }

  /**
   * Sets component which is located as the "secont" splitted area. The method doesn't validate and
   * repaint the splitter.
   *
   * @param component
   */
  public void setSecondComponent(JComponent component) {
    if (mySecondComponent != component) {
      if (mySecondComponent != null) {
        remove(mySecondComponent);
      }
      mySecondComponent = component;
      if (mySecondComponent != null) {
        super.add(mySecondComponent);
        mySecondComponent.invalidate();
      }
    }
  }

  public JPanel getDivider() {
    return myDivider;
  }

  protected class Divider extends JPanel {
    protected boolean myDragging;
    protected Point myPoint;

    public Divider() {
      super(new GridBagLayout());
      setFocusable(false);
      enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK);

      //
      setOrientation(myVerticalSplit);
    }

    private void setOrientation(boolean isVerticalSplit) {
      removeAll();

      if (!myShowDividerControls) {
        return;
      }

      int xMask = isVerticalSplit ? 1 : 0;
      int yMask = isVerticalSplit ? 0 : 1;

      Icon glueIcon = IconLoader.getIcon(isVerticalSplit ? "/general/splitGlueV.png" : "/general/splitGlueH.png");
      int glueFill = isVerticalSplit ? GridBagConstraints.VERTICAL : GridBagConstraints.HORIZONTAL;
      add(new JLabel(glueIcon), new GridBagConstraints(0, 0, 1, 1, 0, 0,
                                                       isVerticalSplit ? GridBagConstraints.EAST : GridBagConstraints.NORTH, glueFill,
                                                       new Insets(0, 0, 0, 0), 0, 0));
      JLabel splitDownlabel = new JLabel(IconLoader.getIcon(isVerticalSplit ? "/general/splitDown.png" : "/general/splitRight.png"));
      splitDownlabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      splitDownlabel.setToolTipText(isVerticalSplit ? UIBundle.message("splitter.down.tooltip.text") : UIBundle
        .message("splitter.right.tooltip.text"));
      splitDownlabel.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
          setProportion(1.0f - getMinProportion(mySecondComponent));
        }
      });
      add(splitDownlabel, new GridBagConstraints(isVerticalSplit ? 1 : 0, isVerticalSplit ? 0 : 5, 1, 1, 0, 0, GridBagConstraints.CENTER,
                                                 GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
      //
      add(new JLabel(glueIcon),
          new GridBagConstraints(2 * xMask, 2 * yMask, 1, 1, 0, 0, GridBagConstraints.CENTER, glueFill, new Insets(0, 0, 0, 0), 0, 0));
      JLabel splitCenterlabel = new JLabel(IconLoader.getIcon(isVerticalSplit ? "/general/splitCenterV.png" : "/general/splitCenterH.png"));
      splitCenterlabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      splitCenterlabel.setToolTipText(UIBundle.message("splitter.center.tooltip.text"));
      splitCenterlabel.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
          setProportion(.5f);
        }
      });
      add(splitCenterlabel, new GridBagConstraints(3 * xMask, 3 * yMask, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
                                                   new Insets(0, 0, 0, 0), 0, 0));
      add(new JLabel(glueIcon),
          new GridBagConstraints(4 * xMask, 4 * yMask, 1, 1, 0, 0, GridBagConstraints.CENTER, glueFill, new Insets(0, 0, 0, 0), 0, 0));
      //
      JLabel splitUpLabel = new JLabel(IconLoader.getIcon(isVerticalSplit ? "/general/splitUp.png" : "/general/splitLeft.png"));
      splitUpLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      splitUpLabel.setToolTipText(isVerticalSplit ? UIBundle.message("splitter.up.tooltip.text") : UIBundle
        .message("splitter.left.tooltip.text"));
      splitUpLabel.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
          setProportion(getMinProportion(myFirstComponent));
        }
      });
      add(splitUpLabel, new GridBagConstraints(isVerticalSplit ? 5 : 0, isVerticalSplit ? 0 : 1, 1, 1, 0, 0, GridBagConstraints.CENTER,
                                               GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
      add(new JLabel(glueIcon), new GridBagConstraints(6 * xMask, 6 * yMask, 1, 1, 0, 0,
                                                       isVerticalSplit ? GridBagConstraints.WEST : GridBagConstraints.SOUTH, glueFill,
                                                       new Insets(0, 0, 0, 0), 0, 0));
    }

    protected void processMouseMotionEvent(MouseEvent e) {
      super.processMouseMotionEvent(e);
      if (MouseEvent.MOUSE_DRAGGED == e.getID()) {
        myDragging = true;
        setCursor(
          getOrientation() ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
        myPoint = SwingUtilities.convertPoint(this, e.getPoint(), Splitter.this);
        float proportion;
        if (getOrientation()) {
          if (getHeight() > 0) {
            proportion = Math.min(1.0f, Math.max(getMinProportion(myFirstComponent), (float)myPoint.y / (float)Splitter.this.getHeight()));
            setProportion(proportion);
          }
        }
        else {
          if (getWidth() > 0) {
            proportion = Math.min(1.0f, Math.max(getMinProportion(myFirstComponent), (float)myPoint.x / (float)Splitter.this.getWidth()));
            setProportion(proportion);
          }
        }
      }
    }

    private float getMinProportion(JComponent component) {
      if (isHonorMinimumSize()) {
        if (component != null && myFirstComponent != null && myFirstComponent.isVisible() && mySecondComponent != null &&
            mySecondComponent.isVisible()) {
          if (getOrientation()) {
            return (float)component.getMinimumSize().height / (float)(Splitter.this.getHeight() - getDividerWidth());
          }
          else {
            return (float)component.getMinimumSize().width / (float)(Splitter.this.getWidth() - getDividerWidth());
          }
        }
      }
      return 0.0f;
    }

    protected void processMouseEvent(MouseEvent e) {
      super.processMouseEvent(e);
      switch (e.getID()) {
        case MouseEvent.MOUSE_ENTERED: {
          setCursor(getOrientation() ? Cursor.getPredefinedCursor(9) : Cursor.getPredefinedCursor(11));
          break;
        }
        case MouseEvent.MOUSE_EXITED: {
          if (!myDragging) {
            setCursor(Cursor.getPredefinedCursor(0));
          }
          break;
        }
        case MouseEvent.MOUSE_PRESSED: {
          setCursor(getOrientation() ? Cursor.getPredefinedCursor(9) : Cursor.getPredefinedCursor(11));
          break;
        }
        case MouseEvent.MOUSE_RELEASED: {
          myDragging = false;
          myPoint = null;
          break;
        }
        case MouseEvent.MOUSE_CLICKED: {
          if (e.getClickCount() == 2) {
            Splitter.this.setProportion(.5f);
          }
          break;
        }
      }
    }
  }
}
TOP

Related Classes of com.intellij.openapi.ui.Splitter$Divider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.