Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   
   27   
   28   package javax.swing.plaf.basic;
   29   
   30   
   31   
   32   import java.awt;
   33   import java.awt.event;
   34   import javax.swing;
   35   import javax.swing.event;
   36   import javax.swing.plaf;
   37   import javax.swing.border.Border;
   38   import java.beans;
   39   import sun.swing.DefaultLookup;
   40   
   41   
   42   
   43   /**
   44    * Divider used by BasicSplitPaneUI. Subclassers may wish to override
   45    * paint to do something more interesting.
   46    * The border effect is drawn in BasicSplitPaneUI, so if you don't like
   47    * that border, reset it there.
   48    * To conditionally drag from certain areas subclass mousePressed and
   49    * call super when you wish the dragging to begin.
   50    * <p>
   51    * <strong>Warning:</strong>
   52    * Serialized objects of this class will not be compatible with
   53    * future Swing releases. The current serialization support is
   54    * appropriate for short term storage or RMI between applications running
   55    * the same version of Swing.  As of 1.4, support for long term storage
   56    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   57    * has been added to the <code>java.beans</code> package.
   58    * Please see {@link java.beans.XMLEncoder}.
   59    *
   60    * @author Scott Violet
   61    */
   62   public class BasicSplitPaneDivider extends Container
   63       implements PropertyChangeListener
   64   {
   65       /**
   66        * Width or height of the divider based on orientation
   67        * BasicSplitPaneUI adds two to this.
   68        */
   69       protected static final int ONE_TOUCH_SIZE = 6;
   70       protected static final int ONE_TOUCH_OFFSET = 2;
   71   
   72       /**
   73        * Handles mouse dragging message to do the actual dragging.
   74        */
   75       protected DragController dragger;
   76   
   77       /**
   78        * UI this instance was created from.
   79        */
   80       protected BasicSplitPaneUI splitPaneUI;
   81   
   82       /**
   83        * Size of the divider.
   84        */
   85       protected int dividerSize = 0; // default - SET TO 0???
   86   
   87       /**
   88        * Divider that is used for noncontinuous layout mode.
   89        */
   90       protected Component hiddenDivider;
   91   
   92       /**
   93        * JSplitPane the receiver is contained in.
   94        */
   95       protected JSplitPane splitPane;
   96   
   97       /**
   98        * Handles mouse events from both this class, and the split pane.
   99        * Mouse events are handled for the splitpane since you want to be able
  100        * to drag when clicking on the border of the divider, which is not
  101        * drawn by the divider.
  102        */
  103       protected MouseHandler mouseHandler;
  104   
  105       /**
  106        * Orientation of the JSplitPane.
  107        */
  108       protected int orientation;
  109   
  110       /**
  111        * Button for quickly toggling the left component.
  112        */
  113       protected JButton leftButton;
  114   
  115       /**
  116        * Button for quickly toggling the right component.
  117        */
  118       protected JButton rightButton;
  119   
  120       /** Border. */
  121       private Border border;
  122   
  123       /**
  124        * Is the mouse over the divider?
  125        */
  126       private boolean mouseOver;
  127   
  128       private int oneTouchSize;
  129       private int oneTouchOffset;
  130   
  131       /**
  132        * If true the one touch buttons are centered on the divider.
  133        */
  134       private boolean centerOneTouchButtons;
  135   
  136   
  137       /**
  138        * Creates an instance of BasicSplitPaneDivider. Registers this
  139        * instance for mouse events and mouse dragged events.
  140        */
  141       public BasicSplitPaneDivider(BasicSplitPaneUI ui) {
  142           oneTouchSize = DefaultLookup.getInt(ui.getSplitPane(), ui,
  143                   "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE);
  144           oneTouchOffset = DefaultLookup.getInt(ui.getSplitPane(), ui,
  145                   "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET);
  146           centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(),
  147                    ui, "SplitPane.centerOneTouchButtons", true);
  148           setLayout(new DividerLayout());
  149           setBasicSplitPaneUI(ui);
  150           orientation = splitPane.getOrientation();
  151           setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
  152                     Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
  153                     Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
  154           setBackground(UIManager.getColor("SplitPane.background"));
  155       }
  156   
  157       private void revalidateSplitPane() {
  158           invalidate();
  159           if (splitPane != null) {
  160               splitPane.revalidate();
  161           }
  162       }
  163   
  164       /**
  165        * Sets the SplitPaneUI that is using the receiver.
  166        */
  167       public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) {
  168           if (splitPane != null) {
  169               splitPane.removePropertyChangeListener(this);
  170              if (mouseHandler != null) {
  171                  splitPane.removeMouseListener(mouseHandler);
  172                  splitPane.removeMouseMotionListener(mouseHandler);
  173                  removeMouseListener(mouseHandler);
  174                  removeMouseMotionListener(mouseHandler);
  175                  mouseHandler = null;
  176              }
  177           }
  178           splitPaneUI = newUI;
  179           if (newUI != null) {
  180               splitPane = newUI.getSplitPane();
  181               if (splitPane != null) {
  182                   if (mouseHandler == null) mouseHandler = new MouseHandler();
  183                   splitPane.addMouseListener(mouseHandler);
  184                   splitPane.addMouseMotionListener(mouseHandler);
  185                   addMouseListener(mouseHandler);
  186                   addMouseMotionListener(mouseHandler);
  187                   splitPane.addPropertyChangeListener(this);
  188                   if (splitPane.isOneTouchExpandable()) {
  189                       oneTouchExpandableChanged();
  190                   }
  191               }
  192           }
  193           else {
  194               splitPane = null;
  195           }
  196       }
  197   
  198   
  199       /**
  200        * Returns the <code>SplitPaneUI</code> the receiver is currently
  201        * in.
  202        */
  203       public BasicSplitPaneUI getBasicSplitPaneUI() {
  204           return splitPaneUI;
  205       }
  206   
  207   
  208       /**
  209        * Sets the size of the divider to <code>newSize</code>. That is
  210        * the width if the splitpane is <code>HORIZONTAL_SPLIT</code>, or
  211        * the height of <code>VERTICAL_SPLIT</code>.
  212        */
  213       public void setDividerSize(int newSize) {
  214           dividerSize = newSize;
  215       }
  216   
  217   
  218       /**
  219        * Returns the size of the divider, that is the width if the splitpane
  220        * is HORIZONTAL_SPLIT, or the height of VERTICAL_SPLIT.
  221        */
  222       public int getDividerSize() {
  223           return dividerSize;
  224       }
  225   
  226   
  227       /**
  228        * Sets the border of this component.
  229        * @since 1.3
  230        */
  231       public void setBorder(Border border) {
  232           Border         oldBorder = this.border;
  233   
  234           this.border = border;
  235       }
  236   
  237       /**
  238        * Returns the border of this component or null if no border is
  239        * currently set.
  240        *
  241        * @return the border object for this component
  242        * @see #setBorder
  243        * @since 1.3
  244        */
  245       public Border getBorder() {
  246           return border;
  247       }
  248   
  249       /**
  250        * If a border has been set on this component, returns the
  251        * border's insets, else calls super.getInsets.
  252        *
  253        * @return the value of the insets property.
  254        * @see #setBorder
  255        */
  256       public Insets getInsets() {
  257           Border    border = getBorder();
  258   
  259           if (border != null) {
  260               return border.getBorderInsets(this);
  261           }
  262           return super.getInsets();
  263       }
  264   
  265       /**
  266        * Sets whether or not the mouse is currently over the divider.
  267        *
  268        * @param mouseOver whether or not the mouse is currently over the divider
  269        * @since 1.5
  270        */
  271       protected void setMouseOver(boolean mouseOver) {
  272           this.mouseOver = mouseOver;
  273       }
  274   
  275       /**
  276        * Returns whether or not the mouse is currently over the divider
  277        *
  278        * @return whether or not the mouse is currently over the divider
  279        * @since 1.5
  280        */
  281       public boolean isMouseOver() {
  282           return mouseOver;
  283       }
  284   
  285       /**
  286        * Returns dividerSize x dividerSize
  287        */
  288       public Dimension getPreferredSize() {
  289           // Ideally this would return the size from the layout manager,
  290           // but that could result in the layed out size being different from
  291           // the dividerSize, which may break developers as well as
  292           // BasicSplitPaneUI.
  293           if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
  294               return new Dimension(getDividerSize(), 1);
  295           }
  296           return new Dimension(1, getDividerSize());
  297       }
  298   
  299       /**
  300        * Returns dividerSize x dividerSize
  301        */
  302       public Dimension getMinimumSize() {
  303           return getPreferredSize();
  304       }
  305   
  306   
  307       /**
  308        * Property change event, presumably from the JSplitPane, will message
  309        * updateOrientation if necessary.
  310        */
  311       public void propertyChange(PropertyChangeEvent e) {
  312           if (e.getSource() == splitPane) {
  313               if (e.getPropertyName() == JSplitPane.ORIENTATION_PROPERTY) {
  314                   orientation = splitPane.getOrientation();
  315                   setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
  316                             Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
  317                             Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
  318                   revalidateSplitPane();
  319               }
  320               else if (e.getPropertyName() == JSplitPane.
  321                         ONE_TOUCH_EXPANDABLE_PROPERTY) {
  322                   oneTouchExpandableChanged();
  323               }
  324           }
  325       }
  326   
  327   
  328       /**
  329        * Paints the divider.
  330        */
  331       public void paint(Graphics g) {
  332         super.paint(g);
  333   
  334         // Paint the border.
  335         Border   border = getBorder();
  336   
  337         if (border != null) {
  338             Dimension     size = getSize();
  339   
  340             border.paintBorder(this, g, 0, 0, size.width, size.height);
  341         }
  342       }
  343   
  344   
  345       /**
  346        * Messaged when the oneTouchExpandable value of the JSplitPane the
  347        * receiver is contained in changes. Will create the
  348        * <code>leftButton</code> and <code>rightButton</code> if they
  349        * are null. invalidates the receiver as well.
  350        */
  351       protected void oneTouchExpandableChanged() {
  352           if (!DefaultLookup.getBoolean(splitPane, splitPaneUI,
  353                              "SplitPane.supportsOneTouchButtons", true)) {
  354               // Look and feel doesn't want to support one touch buttons, bail.
  355               return;
  356           }
  357           if (splitPane.isOneTouchExpandable() &&
  358               leftButton == null &&
  359               rightButton == null) {
  360               /* Create the left button and add an action listener to
  361                  expand/collapse it. */
  362               leftButton = createLeftOneTouchButton();
  363               if (leftButton != null)
  364                   leftButton.addActionListener(new OneTouchActionHandler(true));
  365   
  366   
  367               /* Create the right button and add an action listener to
  368                  expand/collapse it. */
  369               rightButton = createRightOneTouchButton();
  370               if (rightButton != null)
  371                   rightButton.addActionListener(new OneTouchActionHandler
  372                       (false));
  373   
  374               if (leftButton != null && rightButton != null) {
  375                   add(leftButton);
  376                   add(rightButton);
  377               }
  378           }
  379           revalidateSplitPane();
  380       }
  381   
  382   
  383       /**
  384        * Creates and return an instance of JButton that can be used to
  385        * collapse the left component in the split pane.
  386        */
  387       protected JButton createLeftOneTouchButton() {
  388           JButton b = new JButton() {
  389               public void setBorder(Border b) {
  390               }
  391               public void paint(Graphics g) {
  392                   if (splitPane != null) {
  393                       int[]   xs = new int[3];
  394                       int[]   ys = new int[3];
  395                       int     blockSize;
  396   
  397                       // Fill the background first ...
  398                       g.setColor(this.getBackground());
  399                       g.fillRect(0, 0, this.getWidth(),
  400                                  this.getHeight());
  401   
  402                       // ... then draw the arrow.
  403                       g.setColor(Color.black);
  404                       if (orientation == JSplitPane.VERTICAL_SPLIT) {
  405                           blockSize = Math.min(getHeight(), oneTouchSize);
  406                           xs[0] = blockSize;
  407                           xs[1] = 0;
  408                           xs[2] = blockSize << 1;
  409                           ys[0] = 0;
  410                           ys[1] = ys[2] = blockSize;
  411                           g.drawPolygon(xs, ys, 3); // Little trick to make the
  412                                                     // arrows of equal size
  413                       }
  414                       else {
  415                           blockSize = Math.min(getWidth(), oneTouchSize);
  416                           xs[0] = xs[2] = blockSize;
  417                           xs[1] = 0;
  418                           ys[0] = 0;
  419                           ys[1] = blockSize;
  420                           ys[2] = blockSize << 1;
  421                       }
  422                       g.fillPolygon(xs, ys, 3);
  423                   }
  424               }
  425               // Don't want the button to participate in focus traversable.
  426               public boolean isFocusTraversable() {
  427                   return false;
  428               }
  429           };
  430           b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
  431           b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  432           b.setFocusPainted(false);
  433           b.setBorderPainted(false);
  434           b.setRequestFocusEnabled(false);
  435           return b;
  436       }
  437   
  438   
  439       /**
  440        * Creates and return an instance of JButton that can be used to
  441        * collapse the right component in the split pane.
  442        */
  443       protected JButton createRightOneTouchButton() {
  444           JButton b = new JButton() {
  445               public void setBorder(Border border) {
  446               }
  447               public void paint(Graphics g) {
  448                   if (splitPane != null) {
  449                       int[]          xs = new int[3];
  450                       int[]          ys = new int[3];
  451                       int            blockSize;
  452   
  453                       // Fill the background first ...
  454                       g.setColor(this.getBackground());
  455                       g.fillRect(0, 0, this.getWidth(),
  456                                  this.getHeight());
  457   
  458                       // ... then draw the arrow.
  459                       if (orientation == JSplitPane.VERTICAL_SPLIT) {
  460                           blockSize = Math.min(getHeight(), oneTouchSize);
  461                           xs[0] = blockSize;
  462                           xs[1] = blockSize << 1;
  463                           xs[2] = 0;
  464                           ys[0] = blockSize;
  465                           ys[1] = ys[2] = 0;
  466                       }
  467                       else {
  468                           blockSize = Math.min(getWidth(), oneTouchSize);
  469                           xs[0] = xs[2] = 0;
  470                           xs[1] = blockSize;
  471                           ys[0] = 0;
  472                           ys[1] = blockSize;
  473                           ys[2] = blockSize << 1;
  474                       }
  475                       g.setColor(Color.black);
  476                       g.fillPolygon(xs, ys, 3);
  477                   }
  478               }
  479               // Don't want the button to participate in focus traversable.
  480               public boolean isFocusTraversable() {
  481                   return false;
  482               }
  483           };
  484           b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
  485           b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  486           b.setFocusPainted(false);
  487           b.setBorderPainted(false);
  488           b.setRequestFocusEnabled(false);
  489           return b;
  490       }
  491   
  492   
  493       /**
  494        * Message to prepare for dragging. This messages the BasicSplitPaneUI
  495        * with startDragging.
  496        */
  497       protected void prepareForDragging() {
  498           splitPaneUI.startDragging();
  499       }
  500   
  501   
  502       /**
  503        * Messages the BasicSplitPaneUI with dragDividerTo that this instance
  504        * is contained in.
  505        */
  506       protected void dragDividerTo(int location) {
  507           splitPaneUI.dragDividerTo(location);
  508       }
  509   
  510   
  511       /**
  512        * Messages the BasicSplitPaneUI with finishDraggingTo that this instance
  513        * is contained in.
  514        */
  515       protected void finishDraggingTo(int location) {
  516           splitPaneUI.finishDraggingTo(location);
  517       }
  518   
  519   
  520       /**
  521        * MouseHandler is responsible for converting mouse events
  522        * (released, dragged...) into the appropriate DragController
  523        * methods.
  524        * <p>
  525        */
  526       protected class MouseHandler extends MouseAdapter
  527               implements MouseMotionListener
  528       {
  529           /**
  530            * Starts the dragging session by creating the appropriate instance
  531            * of DragController.
  532            */
  533           public void mousePressed(MouseEvent e) {
  534               if ((e.getSource() == BasicSplitPaneDivider.this ||
  535                    e.getSource() == splitPane) &&
  536                   dragger == null &&splitPane.isEnabled()) {
  537                   Component            newHiddenDivider = splitPaneUI.
  538                                        getNonContinuousLayoutDivider();
  539   
  540                   if (hiddenDivider != newHiddenDivider) {
  541                       if (hiddenDivider != null) {
  542                           hiddenDivider.removeMouseListener(this);
  543                           hiddenDivider.removeMouseMotionListener(this);
  544                       }
  545                       hiddenDivider = newHiddenDivider;
  546                       if (hiddenDivider != null) {
  547                           hiddenDivider.addMouseMotionListener(this);
  548                           hiddenDivider.addMouseListener(this);
  549                       }
  550                   }
  551                   if (splitPane.getLeftComponent() != null &&
  552                       splitPane.getRightComponent() != null) {
  553                       if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
  554                           dragger = new DragController(e);
  555                       }
  556                       else {
  557                           dragger = new VerticalDragController(e);
  558                       }
  559                       if (!dragger.isValid()) {
  560                           dragger = null;
  561                       }
  562                       else {
  563                           prepareForDragging();
  564                           dragger.continueDrag(e);
  565                       }
  566                   }
  567                   e.consume();
  568               }
  569           }
  570   
  571   
  572           /**
  573            * If dragger is not null it is messaged with completeDrag.
  574            */
  575           public void mouseReleased(MouseEvent e) {
  576               if (dragger != null) {
  577                   if (e.getSource() == splitPane) {
  578                       dragger.completeDrag(e.getX(), e.getY());
  579                   }
  580                   else if (e.getSource() == BasicSplitPaneDivider.this) {
  581                       Point   ourLoc = getLocation();
  582   
  583                       dragger.completeDrag(e.getX() + ourLoc.x,
  584                                            e.getY() + ourLoc.y);
  585                   }
  586                   else if (e.getSource() == hiddenDivider) {
  587                       Point   hDividerLoc = hiddenDivider.getLocation();
  588                       int     ourX = e.getX() + hDividerLoc.x;
  589                       int     ourY = e.getY() + hDividerLoc.y;
  590   
  591                       dragger.completeDrag(ourX, ourY);
  592                   }
  593                   dragger = null;
  594                   e.consume();
  595               }
  596           }
  597   
  598   
  599           //
  600           // MouseMotionListener
  601           //
  602   
  603           /**
  604            * If dragger is not null it is messaged with continueDrag.
  605            */
  606           public void mouseDragged(MouseEvent e) {
  607               if (dragger != null) {
  608                   if (e.getSource() == splitPane) {
  609                       dragger.continueDrag(e.getX(), e.getY());
  610                   }
  611                   else if (e.getSource() == BasicSplitPaneDivider.this) {
  612                       Point   ourLoc = getLocation();
  613   
  614                       dragger.continueDrag(e.getX() + ourLoc.x,
  615                                            e.getY() + ourLoc.y);
  616                   }
  617                   else if (e.getSource() == hiddenDivider) {
  618                       Point   hDividerLoc = hiddenDivider.getLocation();
  619                       int     ourX = e.getX() + hDividerLoc.x;
  620                       int     ourY = e.getY() + hDividerLoc.y;
  621   
  622                       dragger.continueDrag(ourX, ourY);
  623                   }
  624                   e.consume();
  625               }
  626           }
  627   
  628   
  629           /**
  630            *  Resets the cursor based on the orientation.
  631            */
  632           public void mouseMoved(MouseEvent e) {
  633           }
  634   
  635           /**
  636            * Invoked when the mouse enters a component.
  637            *
  638            * @param e MouseEvent describing the details of the enter event.
  639            * @since 1.5
  640            */
  641           public void mouseEntered(MouseEvent e) {
  642               if (e.getSource() == BasicSplitPaneDivider.this) {
  643                   setMouseOver(true);
  644               }
  645           }
  646   
  647           /**
  648            * Invoked when the mouse exits a component.
  649            *
  650            * @param e MouseEvent describing the details of the exit event.
  651            * @since 1.5
  652            */
  653           public void mouseExited(MouseEvent e) {
  654               if (e.getSource() == BasicSplitPaneDivider.this) {
  655                   setMouseOver(false);
  656               }
  657           }
  658       }
  659   
  660   
  661       /**
  662        * Handles the events during a dragging session for a
  663        * HORIZONTAL_SPLIT oriented split pane. This continually
  664        * messages <code>dragDividerTo</code> and then when done messages
  665        * <code>finishDraggingTo</code>. When an instance is created it should be
  666        * messaged with <code>isValid</code> to insure that dragging can happen
  667        * (dragging won't be allowed if the two views can not be resized).
  668        * <p>
  669        * <strong>Warning:</strong>
  670        * Serialized objects of this class will not be compatible with
  671        * future Swing releases. The current serialization support is
  672        * appropriate for short term storage or RMI between applications running
  673        * the same version of Swing.  As of 1.4, support for long term storage
  674        * of all JavaBeans<sup><font size="-2">TM</font></sup>
  675        * has been added to the <code>java.beans</code> package.
  676        * Please see {@link java.beans.XMLEncoder}.
  677        */
  678       protected class DragController
  679       {
  680           /**
  681            * Initial location of the divider.
  682            */
  683           int initialX;
  684   
  685           /**
  686            * Maximum and minimum positions to drag to.
  687            */
  688           int maxX, minX;
  689   
  690           /**
  691            * Initial location the mouse down happened at.
  692            */
  693           int offset;
  694   
  695   
  696           protected DragController(MouseEvent e) {
  697               JSplitPane  splitPane = splitPaneUI.getSplitPane();
  698               Component   leftC = splitPane.getLeftComponent();
  699               Component   rightC = splitPane.getRightComponent();
  700   
  701               initialX = getLocation().x;
  702               if (e.getSource() == BasicSplitPaneDivider.this) {
  703                   offset = e.getX();
  704               }
  705               else { // splitPane
  706                   offset = e.getX() - initialX;
  707               }
  708               if (leftC == null || rightC == null || offset < -1 ||
  709                   offset >= getSize().width) {
  710                   // Don't allow dragging.
  711                   maxX = -1;
  712               }
  713               else {
  714                   Insets      insets = splitPane.getInsets();
  715   
  716                   if (leftC.isVisible()) {
  717                       minX = leftC.getMinimumSize().width;
  718                       if (insets != null) {
  719                           minX += insets.left;
  720                       }
  721                   }
  722                   else {
  723                       minX = 0;
  724                   }
  725                   if (rightC.isVisible()) {
  726                       int right = (insets != null) ? insets.right : 0;
  727                       maxX = Math.max(0, splitPane.getSize().width -
  728                                       (getSize().width + right) -
  729                                       rightC.getMinimumSize().width);
  730                   }
  731                   else {
  732                       int right = (insets != null) ? insets.right : 0;
  733                       maxX = Math.max(0, splitPane.getSize().width -
  734                                       (getSize().width + right));
  735                   }
  736                   if (maxX < minX) minX = maxX = 0;
  737               }
  738           }
  739   
  740   
  741           /**
  742            * Returns true if the dragging session is valid.
  743            */
  744           protected boolean isValid() {
  745               return (maxX > 0);
  746           }
  747   
  748   
  749           /**
  750            * Returns the new position to put the divider at based on
  751            * the passed in MouseEvent.
  752            */
  753           protected int positionForMouseEvent(MouseEvent e) {
  754               int newX = (e.getSource() == BasicSplitPaneDivider.this) ?
  755                           (e.getX() + getLocation().x) : e.getX();
  756   
  757               newX = Math.min(maxX, Math.max(minX, newX - offset));
  758               return newX;
  759           }
  760   
  761   
  762           /**
  763            * Returns the x argument, since this is used for horizontal
  764            * splits.
  765            */
  766           protected int getNeededLocation(int x, int y) {
  767               int newX;
  768   
  769               newX = Math.min(maxX, Math.max(minX, x - offset));
  770               return newX;
  771           }
  772   
  773   
  774           protected void continueDrag(int newX, int newY) {
  775               dragDividerTo(getNeededLocation(newX, newY));
  776           }
  777   
  778   
  779           /**
  780            * Messages dragDividerTo with the new location for the mouse
  781            * event.
  782            */
  783           protected void continueDrag(MouseEvent e) {
  784               dragDividerTo(positionForMouseEvent(e));
  785           }
  786   
  787   
  788           protected void completeDrag(int x, int y) {
  789               finishDraggingTo(getNeededLocation(x, y));
  790           }
  791   
  792   
  793           /**
  794            * Messages finishDraggingTo with the new location for the mouse
  795            * event.
  796            */
  797           protected void completeDrag(MouseEvent e) {
  798               finishDraggingTo(positionForMouseEvent(e));
  799           }
  800       } // End of BasicSplitPaneDivider.DragController
  801   
  802   
  803       /**
  804        * Handles the events during a dragging session for a
  805        * VERTICAL_SPLIT oriented split pane. This continually
  806        * messages <code>dragDividerTo</code> and then when done messages
  807        * <code>finishDraggingTo</code>. When an instance is created it should be
  808        * messaged with <code>isValid</code> to insure that dragging can happen
  809        * (dragging won't be allowed if the two views can not be resized).
  810        */
  811       protected class VerticalDragController extends DragController
  812       {
  813           /* DragControllers ivars are now in terms of y, not x. */
  814           protected VerticalDragController(MouseEvent e) {
  815               super(e);
  816               JSplitPane splitPane = splitPaneUI.getSplitPane();
  817               Component  leftC = splitPane.getLeftComponent();
  818               Component  rightC = splitPane.getRightComponent();
  819   
  820               initialX = getLocation().y;
  821               if (e.getSource() == BasicSplitPaneDivider.this) {
  822                   offset = e.getY();
  823               }
  824               else {
  825                   offset = e.getY() - initialX;
  826               }
  827               if (leftC == null || rightC == null || offset < -1 ||
  828                   offset > getSize().height) {
  829                   // Don't allow dragging.
  830                   maxX = -1;
  831               }
  832               else {
  833                   Insets     insets = splitPane.getInsets();
  834   
  835                   if (leftC.isVisible()) {
  836                       minX = leftC.getMinimumSize().height;
  837                       if (insets != null) {
  838                           minX += insets.top;
  839                       }
  840                   }
  841                   else {
  842                       minX = 0;
  843                   }
  844                   if (rightC.isVisible()) {
  845                       int    bottom = (insets != null) ? insets.bottom : 0;
  846   
  847                       maxX = Math.max(0, splitPane.getSize().height -
  848                                       (getSize().height + bottom) -
  849                                       rightC.getMinimumSize().height);
  850                   }
  851                   else {
  852                       int    bottom = (insets != null) ? insets.bottom : 0;
  853   
  854                       maxX = Math.max(0, splitPane.getSize().height -
  855                                       (getSize().height + bottom));
  856                   }
  857                   if (maxX < minX) minX = maxX = 0;
  858               }
  859           }
  860   
  861   
  862           /**
  863            * Returns the y argument, since this is used for vertical
  864            * splits.
  865            */
  866           protected int getNeededLocation(int x, int y) {
  867               int newY;
  868   
  869               newY = Math.min(maxX, Math.max(minX, y - offset));
  870               return newY;
  871           }
  872   
  873   
  874           /**
  875            * Returns the new position to put the divider at based on
  876            * the passed in MouseEvent.
  877            */
  878           protected int positionForMouseEvent(MouseEvent e) {
  879               int newY = (e.getSource() == BasicSplitPaneDivider.this) ?
  880                           (e.getY() + getLocation().y) : e.getY();
  881   
  882   
  883               newY = Math.min(maxX, Math.max(minX, newY - offset));
  884               return newY;
  885           }
  886       } // End of BasicSplitPaneDividier.VerticalDragController
  887   
  888   
  889       /**
  890        * Used to layout a <code>BasicSplitPaneDivider</code>.
  891        * Layout for the divider
  892        * involves appropriately moving the left/right buttons around.
  893        * <p>
  894        */
  895       protected class DividerLayout implements LayoutManager
  896       {
  897           public void layoutContainer(Container c) {
  898               if (leftButton != null && rightButton != null &&
  899                   c == BasicSplitPaneDivider.this) {
  900                   if (splitPane.isOneTouchExpandable()) {
  901                       Insets insets = getInsets();
  902   
  903                       if (orientation == JSplitPane.VERTICAL_SPLIT) {
  904                           int extraX = (insets != null) ? insets.left : 0;
  905                           int blockSize = getHeight();
  906   
  907                           if (insets != null) {
  908                               blockSize -= (insets.top + insets.bottom);
  909                               blockSize = Math.max(blockSize, 0);
  910                           }
  911                           blockSize = Math.min(blockSize, oneTouchSize);
  912   
  913                           int y = (c.getSize().height - blockSize) / 2;
  914   
  915                           if (!centerOneTouchButtons) {
  916                               y = (insets != null) ? insets.top : 0;
  917                               extraX = 0;
  918                           }
  919                           leftButton.setBounds(extraX + oneTouchOffset, y,
  920                                                blockSize * 2, blockSize);
  921                           rightButton.setBounds(extraX + oneTouchOffset +
  922                                                 oneTouchSize * 2, y,
  923                                                 blockSize * 2, blockSize);
  924                       }
  925                       else {
  926                           int extraY = (insets != null) ? insets.top : 0;
  927                           int blockSize = getWidth();
  928   
  929                           if (insets != null) {
  930                               blockSize -= (insets.left + insets.right);
  931                               blockSize = Math.max(blockSize, 0);
  932                           }
  933                           blockSize = Math.min(blockSize, oneTouchSize);
  934   
  935                           int x = (c.getSize().width - blockSize) / 2;
  936   
  937                           if (!centerOneTouchButtons) {
  938                               x = (insets != null) ? insets.left : 0;
  939                               extraY = 0;
  940                           }
  941   
  942                           leftButton.setBounds(x, extraY + oneTouchOffset,
  943                                                blockSize, blockSize * 2);
  944                           rightButton.setBounds(x, extraY + oneTouchOffset +
  945                                                 oneTouchSize * 2, blockSize,
  946                                                 blockSize * 2);
  947                       }
  948                   }
  949                   else {
  950                       leftButton.setBounds(-5, -5, 1, 1);
  951                       rightButton.setBounds(-5, -5, 1, 1);
  952                   }
  953               }
  954           }
  955   
  956   
  957           public Dimension minimumLayoutSize(Container c) {
  958               // NOTE: This isn't really used, refer to
  959               // BasicSplitPaneDivider.getPreferredSize for the reason.
  960               // I leave it in hopes of having this used at some point.
  961               if (c != BasicSplitPaneDivider.this || splitPane == null) {
  962                   return new Dimension(0,0);
  963               }
  964               Dimension buttonMinSize = null;
  965   
  966               if (splitPane.isOneTouchExpandable() && leftButton != null) {
  967                   buttonMinSize = leftButton.getMinimumSize();
  968               }
  969   
  970               Insets insets = getInsets();
  971               int width = getDividerSize();
  972               int height = width;
  973   
  974               if (orientation == JSplitPane.VERTICAL_SPLIT) {
  975                   if (buttonMinSize != null) {
  976                       int size = buttonMinSize.height;
  977                       if (insets != null) {
  978                           size += insets.top + insets.bottom;
  979                       }
  980                       height = Math.max(height, size);
  981                   }
  982                   width = 1;
  983               }
  984               else {
  985                   if (buttonMinSize != null) {
  986                       int size = buttonMinSize.width;
  987                       if (insets != null) {
  988                           size += insets.left + insets.right;
  989                       }
  990                       width = Math.max(width, size);
  991                   }
  992                   height = 1;
  993               }
  994               return new Dimension(width, height);
  995           }
  996   
  997   
  998           public Dimension preferredLayoutSize(Container c) {
  999               return minimumLayoutSize(c);
 1000           }
 1001   
 1002   
 1003           public void removeLayoutComponent(Component c) {}
 1004   
 1005           public void addLayoutComponent(String string, Component c) {}
 1006       } // End of class BasicSplitPaneDivider.DividerLayout
 1007   
 1008   
 1009       /**
 1010        * Listeners installed on the one touch expandable buttons.
 1011        */
 1012       private class OneTouchActionHandler implements ActionListener {
 1013           /** True indicates the resize should go the minimum (top or left)
 1014            * vs false which indicates the resize should go to the maximum.
 1015            */
 1016           private boolean toMinimum;
 1017   
 1018           OneTouchActionHandler(boolean toMinimum) {
 1019               this.toMinimum = toMinimum;
 1020           }
 1021   
 1022           public void actionPerformed(ActionEvent e) {
 1023               Insets  insets = splitPane.getInsets();
 1024               int     lastLoc = splitPane.getLastDividerLocation();
 1025               int     currentLoc = splitPaneUI.getDividerLocation(splitPane);
 1026               int     newLoc;
 1027   
 1028               // We use the location from the UI directly, as the location the
 1029               // JSplitPane itself maintains is not necessarly correct.
 1030               if (toMinimum) {
 1031                   if (orientation == JSplitPane.VERTICAL_SPLIT) {
 1032                       if (currentLoc >= (splitPane.getHeight() -
 1033                                          insets.bottom - getHeight())) {
 1034                           int maxLoc = splitPane.getMaximumDividerLocation();
 1035                           newLoc = Math.min(lastLoc, maxLoc);
 1036                           splitPaneUI.setKeepHidden(false);
 1037                       }
 1038                       else {
 1039                           newLoc = insets.top;
 1040                           splitPaneUI.setKeepHidden(true);
 1041                       }
 1042                   }
 1043                   else {
 1044                       if (currentLoc >= (splitPane.getWidth() -
 1045                                          insets.right - getWidth())) {
 1046                           int maxLoc = splitPane.getMaximumDividerLocation();
 1047                           newLoc = Math.min(lastLoc, maxLoc);
 1048                           splitPaneUI.setKeepHidden(false);
 1049                       }
 1050                       else {
 1051                           newLoc = insets.left;
 1052                           splitPaneUI.setKeepHidden(true);
 1053                       }
 1054                   }
 1055               }
 1056               else {
 1057                   if (orientation == JSplitPane.VERTICAL_SPLIT) {
 1058                       if (currentLoc == insets.top) {
 1059                           int maxLoc = splitPane.getMaximumDividerLocation();
 1060                           newLoc = Math.min(lastLoc, maxLoc);
 1061                           splitPaneUI.setKeepHidden(false);
 1062                       }
 1063                       else {
 1064                           newLoc = splitPane.getHeight() - getHeight() -
 1065                                    insets.top;
 1066                           splitPaneUI.setKeepHidden(true);
 1067                       }
 1068                   }
 1069                   else {
 1070                       if (currentLoc == insets.left) {
 1071                           int maxLoc = splitPane.getMaximumDividerLocation();
 1072                           newLoc = Math.min(lastLoc, maxLoc);
 1073                           splitPaneUI.setKeepHidden(false);
 1074                       }
 1075                       else {
 1076                           newLoc = splitPane.getWidth() - getWidth() -
 1077                                    insets.left;
 1078                           splitPaneUI.setKeepHidden(true);
 1079                       }
 1080                   }
 1081               }
 1082               if (currentLoc != newLoc) {
 1083                   splitPane.setDividerLocation(newLoc);
 1084                   // We do this in case the dividers notion of the location
 1085                   // differs from the real location.
 1086                   splitPane.setLastDividerLocation(currentLoc);
 1087               }
 1088           }
 1089       } // End of class BasicSplitPaneDivider.LeftActionListener
 1090   }

Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]