All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jidesoft.swing.JideScrollPane Maven / Gradle / Ivy

/*
 * @(#)JideScrollPane.java
 *
 * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
 */
package com.jidesoft.swing;

import javax.swing.*;
import javax.swing.plaf.UIResource;
import java.awt.*;

/**
 * JideScrollPane is an enhanced version of JScrollPane. In JScrollPane, you can
 * have rowHeader and columnHeader. However you can't have rowFooter and columnFooter. However rowFooter and
 * columnFooter are very useful in table. For example they can be used to display "total" or "summary" type of
 * information.
 * 

* Several methods related to rowFooter and columnFooter are added such as {@link #setRowFooter(javax.swing.JViewport)}, * and {@link #setColumnFooter(javax.swing.JViewport)} which will set the viewport to rowFooter and columnFooter area * respectively. The usage of those methods are exactly the same as {@link JScrollPane#setRowHeader(javax.swing.JViewport)}. *

* To fully leverage the power of JideScrollPane, we also create a class called TableScrollPane which is * part of JIDE Grids package. It will allow you to easily create table with row header, row footer and column footer. *

JideScrollPane also provides support for scrollbar corners. You can set them using {@link * #setScrollBarCorner(String, java.awt.Component)}. Available key for scroll bar corner is defined at {@link * JideScrollPaneConstants} which can be access from JideScrollPane. *

* Credit: This implementation of scroll bar corner is based on work from Santhosh Kumar - * [email protected]. */ public class JideScrollPane extends JScrollPane implements JideScrollPaneConstants { /** * The row footer child. Default is null. * * @see #setRowFooter(javax.swing.JViewport) */ protected JViewport _rowFooter; /** * The component under column header. Default is null. * * @see #setSubColumnHeader(javax.swing.JViewport) */ protected JViewport _subColumnHeader; /** * The component under upper left corner. Default is null. * * @see #setCorner(String, java.awt.Component) */ protected Component _subUpperLeft; /** * The component under upper right corner. Default is null. * * @see #setCorner(String, java.awt.Component) */ protected Component _subUpperRight; /** * The column footer child. Default is null. * * @see #setColumnFooter(javax.swing.JViewport) */ protected JViewport _columnFooter; /** * The component to the left of horizontal scroll bar. */ protected Component _hLeft; /** * The component to the right of horizontal scroll bar. */ protected Component _hRight; /** * The component to the top of vertical scroll bar. */ protected Component _vTop; /** * The component to the bottom of vertical scroll bar. */ protected Component _vBottom; private boolean _keepCornerVisible = false; private boolean _horizontalScrollBarCoversWholeWidth; private boolean _verticalScrollBarCoversWholeHeight; private boolean _flatLayout = false; public static final String PROPERTY_HORIZONTAL_SCROLL_BAR_COVERS_WHOLE_WIDTH = "horizontalScrollBarCoversWholeWidth"; public static final String PROPERTY_VERTICAL_SCROLL_BAR_COVERS_WHOLE_HEIGHT = "verticalScrollBarCoversWholeHeight"; public static final String PROPERTY_KEEP_CORNER_VISIBLE = "keepCornerVisible"; public static final String PROPERTY_FLAT_LAYOUT = "flatLayout"; private boolean _columnHeadersHeightUnified; private boolean _columnFootersHeightUnified; public static final String PROPERTY_COLUMN_HEADERS_HEIGHT_UNIFIED = "columnHeadersHeightUnified"; public static final String PROPERTY_COLUMN_FOOTERS_HEIGHT_UNIFIED = "columnFootersHeightUnified"; public static final String CLIENT_PROPERTY_SLAVE_VIEWPORT = "synchronizeViewSlaveViewport"; public static final String CLIENT_PROPERTY_MASTER_VIEWPORT = "synchronizeViewMasterViewport"; /** * Creates a JideScrollPane that displays the view component in a viewport whose view position can be * controlled with a pair of scrollbars. The scrollbar policies specify when the scrollbars are displayed, For * example, if vsbPolicy is VERTICAL_SCROLLBAR_AS_NEEDED then the vertical scrollbar only * appears if the view doesn't fit vertically. The available policy settings are listed at {@link * #setVerticalScrollBarPolicy(int)} and {@link #setHorizontalScrollBarPolicy(int)}. * * @param view the component to display in the scrollpanes viewport * @param vsbPolicy an integer that specifies the vertical scrollbar policy * @param hsbPolicy an integer that specifies the horizontal scrollbar policy * @see #setViewportView(java.awt.Component) */ public JideScrollPane(Component view, int vsbPolicy, int hsbPolicy) { setLayout(new JideScrollPaneLayout.UIResource()); setVerticalScrollBarPolicy(vsbPolicy); setHorizontalScrollBarPolicy(hsbPolicy); setViewport(createViewport()); setVerticalScrollBar(createVerticalScrollBar()); setHorizontalScrollBar(createHorizontalScrollBar()); if (null != view) { setViewportView(view); } setOpaque(true); updateUI(); if (!getComponentOrientation().isLeftToRight()) { viewport.setViewPosition(new Point(Integer.MAX_VALUE, 0)); } } /** * Creates a JideScrollPane that displays the contents of the specified component, where both * horizontal and vertical scrollbars appear whenever the component's contents are larger than the view. * * @param view the component to display in the scrollpane's viewport * @see #setViewportView(java.awt.Component) */ public JideScrollPane(Component view) { this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); } /** * Creates an empty (no viewport view) JideScrollPane with specified scrollbar policies. The available * policy settings are listed at {@link #setVerticalScrollBarPolicy(int)} and {@link * #setHorizontalScrollBarPolicy(int)}. * * @param vsbPolicy an integer that specifies the vertical scrollbar policy * @param hsbPolicy an integer that specifies the horizontal scrollbar policy * @see #setViewportView(java.awt.Component) */ public JideScrollPane(int vsbPolicy, int hsbPolicy) { this(null, vsbPolicy, hsbPolicy); } /** * Creates an empty (no viewport view) JideScrollPane where both horizontal and vertical scrollbars * appear when needed. */ public JideScrollPane() { this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); } @Override public void setViewport(JViewport viewport) { JViewport old = getViewport(); super.setViewport(viewport); if (old != null) { if (rowHeader != null) { JideSwingUtilities.unsynchronizeView(rowHeader, old); } if (_rowFooter != null) { JideSwingUtilities.unsynchronizeView(_rowFooter, old); JideSwingUtilities.unsynchronizeView(old, _rowFooter); } if (_columnFooter != null) { JideSwingUtilities.unsynchronizeView(_columnFooter, old); JideSwingUtilities.unsynchronizeView(old, _columnFooter); } if (columnHeader != null) { JideSwingUtilities.unsynchronizeView(columnHeader, old); } if (_subColumnHeader != null) { JideSwingUtilities.unsynchronizeView(_subColumnHeader, old); JideSwingUtilities.unsynchronizeView(old, _subColumnHeader); } } if (viewport != null) { if (rowHeader != null) { JideSwingUtilities.synchronizeView(rowHeader, getViewport(), SwingConstants.VERTICAL); } if (_rowFooter != null) { JideSwingUtilities.synchronizeView(_rowFooter, getViewport(), SwingConstants.VERTICAL); JideSwingUtilities.synchronizeView(getViewport(), _rowFooter, SwingConstants.VERTICAL); } if (_columnFooter != null) { JideSwingUtilities.synchronizeView(_columnFooter, getViewport(), SwingConstants.HORIZONTAL); JideSwingUtilities.synchronizeView(getViewport(), _columnFooter, SwingConstants.HORIZONTAL); } if (columnHeader != null) { JideSwingUtilities.synchronizeView(columnHeader, getViewport(), SwingConstants.HORIZONTAL); } if (_subColumnHeader != null) { JideSwingUtilities.synchronizeView(_subColumnHeader, getViewport(), SwingConstants.HORIZONTAL); JideSwingUtilities.synchronizeView(getViewport(), _subColumnHeader, SwingConstants.HORIZONTAL); } } } /** * Returns the row footer. * * @return the rowFooter property * * @see #setRowFooter(javax.swing.JViewport) */ public JViewport getRowFooter() { return _rowFooter; } /** * Removes the old rowFooter, if it exists. If the new rowFooter isn't null, syncs the y coordinate of * its viewPosition with the viewport (if there is one) and then adds it to the scrollpane. * * @param rowFooter the new row footer to be used; if null the old row footer is still removed and the * new rowFooter is set to null * @see #getRowFooter * @see #setRowFooterView(java.awt.Component) */ public void setRowFooter(JViewport rowFooter) { JViewport old = getRowFooter(); _rowFooter = rowFooter; if (null != rowFooter) { add(rowFooter, ROW_FOOTER); } else if (null != old) { remove(old); } firePropertyChange("rowFooter", old, rowFooter); revalidate(); repaint(); if (old != null) { JideSwingUtilities.unsynchronizeView(old, getViewport()); JideSwingUtilities.unsynchronizeView(getViewport(), old); } if (rowFooter != null) { JideSwingUtilities.synchronizeView(rowFooter, getViewport(), SwingConstants.VERTICAL); JideSwingUtilities.synchronizeView(getViewport(), rowFooter, SwingConstants.VERTICAL); } } /** * Override setRowHeader method in JScrollPane and synchronize the view with the main viewport. Swing tried to * implement this feature but it will break if the view position changes starts from rowHeader. * * @param rowHeader the new row header */ @Override public void setRowHeader(JViewport rowHeader) { JViewport old = getRowHeader(); super.setRowHeader(rowHeader); if (old != null) { JideSwingUtilities.unsynchronizeView(old, getViewport()); JideSwingUtilities.unsynchronizeView(getViewport(), old); } if (getRowHeader() != null) { JideSwingUtilities.synchronizeView(getRowHeader(), getViewport(), SwingConstants.VERTICAL); JideSwingUtilities.synchronizeView(getViewport(), getRowHeader(), SwingConstants.VERTICAL); } } /** * Creates a row-footer viewport if necessary, sets its view and then adds the row-footer viewport to the * scrollpane. For example: *

     * JScrollPane scrollpane = new JideScrollPane();
     * scrollpane.setViewportView(myBigComponentToScroll);
     * scrollpane.setRowFooterView(myBigComponentsRowFooter);
     * 
* * @param view the component to display as the row footer * @see #setRowFooter(javax.swing.JViewport) * @see JViewport#setView(java.awt.Component) */ public void setRowFooterView(Component view) { if (null == getRowFooter()) { setRowFooter(createViewport()); } getRowFooter().setView(view); } /** * Returns the column footer. * * @return the columnFooter property * * @see #setColumnFooter(javax.swing.JViewport) */ public JViewport getColumnFooter() { return _columnFooter; } /** * Removes the old columnFooter, if it exists. If the new columnFooter isn't null, sync the x * coordinate of the its viewPosition with the viewport (if there is one) and then add it to the scrollpane. * * @param columnFooter the new column footer to be used; if null the old column footer is still removed * and the new columnFooter is set to null * @see #getColumnFooter * @see #setColumnFooterView(java.awt.Component) */ public void setColumnFooter(JViewport columnFooter) { JViewport old = getColumnFooter(); _columnFooter = columnFooter; if (null != columnFooter) { add(columnFooter, COLUMN_FOOTER); } else if (null != old) { remove(old); } firePropertyChange("columnFooter", old, columnFooter); revalidate(); repaint(); if (old != null) { JideSwingUtilities.unsynchronizeView(old, getViewport()); JideSwingUtilities.unsynchronizeView(getViewport(), old); } if (_columnFooter != null) { JideSwingUtilities.synchronizeView(_columnFooter, getViewport(), SwingConstants.HORIZONTAL); JideSwingUtilities.synchronizeView(getViewport(), _columnFooter, SwingConstants.HORIZONTAL); } } /** * Overrides to make column header viewport synchronizing with the main viewport. * * @param columnHeader the column header */ @Override public void setColumnHeader(JViewport columnHeader) { JViewport old = getColumnHeader(); super.setColumnHeader(columnHeader); if (old != null) { JideSwingUtilities.unsynchronizeView(old, getViewport()); } if (getColumnHeader() != null) { JideSwingUtilities.synchronizeView(getColumnHeader(), getViewport(), SwingConstants.HORIZONTAL); } } /** * Returns the sub column header. * * @return the rowSubColumnHeader property * * @see #setSubColumnHeader(javax.swing.JViewport) */ public JViewport getSubColumnHeader() { return _subColumnHeader; } /** * Removes the old sub column header, if it exists. If the new sub column header isn't null, sync the * x coordinate of the its viewPosition with the viewport (if there is one) and then add it to the scroll pane. * * @param subColumnHeader the new sub column header to be used; if null the old sub column header is * still removed and the new sub column header is set to null * @see #getSubColumnHeader() */ public void setSubColumnHeader(JViewport subColumnHeader) { JViewport old = getSubColumnHeader(); _subColumnHeader = subColumnHeader; if (null != subColumnHeader) { add(subColumnHeader, SUB_COLUMN_HEADER); } else if (null != old) { remove(old); } firePropertyChange("subColumnHeader", old, subColumnHeader); revalidate(); repaint(); if (old != null) { JideSwingUtilities.unsynchronizeView(old, getViewport()); JideSwingUtilities.unsynchronizeView(getViewport(), old); } if (_subColumnHeader != null) { JideSwingUtilities.synchronizeView(_subColumnHeader, getViewport(), SwingConstants.HORIZONTAL); JideSwingUtilities.synchronizeView(getViewport(), _subColumnHeader, SwingConstants.HORIZONTAL); } } /** * Creates a column-footer viewport if necessary, sets its view, and then adds the column-footer viewport to the * scrollpane. For example: *
     * JScrollPane scrollpane = new JideScrollPane();
     * scrollpane.setViewportView(myBigComponentToScroll);
     * scrollpane.setColumnFooterView(myBigComponentsColumnFooter);
     * 
* * @param view the component to display as the column footer * @see #setColumnFooter(javax.swing.JViewport) * @see JViewport#setView(java.awt.Component) */ public void setColumnFooterView(Component view) { if (null == getColumnFooter()) { setColumnFooter(createViewport()); } getColumnFooter().setView(view); } /** * Creates a sub-column-header viewport if necessary, sets its view, and then adds the sub-column-header viewport to * the scrollpane. * * @param view the component to display as the sub column header * @see #setSubColumnHeader(javax.swing.JViewport) * @see JViewport#setView(java.awt.Component) */ public void setSubColumnHeaderView(Component view) { if (null == getSubColumnHeader()) { setSubColumnHeader(createViewport()); } getSubColumnHeader().setView(view); } @Override public Component getCorner(String key) { if (key == null) { return null; } if (key.equals(SUB_UPPER_LEFT)) { return _subUpperLeft; } else if (key.equals(SUB_UPPER_RIGHT)) { return _subUpperRight; } return super.getCorner(key); } @Override public void setCorner(String key, Component corner) { if (key == null) { return; } if (key.equals(SUB_UPPER_LEFT) || key.equals(SUB_UPPER_RIGHT)) { Component old; if (key.equals(SUB_UPPER_LEFT)) { old = _subUpperLeft; _subUpperLeft = corner; } else { old = _subUpperRight; _subUpperRight = corner; } if (old != null) { remove(old); } if (corner != null) { add(corner, key); } firePropertyChange(key, old, corner); revalidate(); repaint(); return; } super.setCorner(key, corner); } /** * Returns the component at the specified scroll bar corner. The key value specifying the corner is one * of:
  • {@link JideScrollPane#HORIZONTAL_LEFT}
  • {@link JideScrollPane#HORIZONTAL_RIGHT}
  • {@link * JideScrollPane#VERTICAL_TOP}
  • {@link JideScrollPane#VERTICAL_BOTTOM}
  • {@link * JideScrollPane#HORIZONTAL_LEADING}
  • {@link JideScrollPane#HORIZONTAL_TRAILING}
* * @param key one of the values as shown above * @return one of the components listed below or null if key is invalid:
    *
  • lowerLeft
  • lowerRight
  • upperLeft
  • upperRight
* * @see #setCorner(String, java.awt.Component) */ public Component getScrollBarCorner(String key) { boolean isLeftToRight = getComponentOrientation().isLeftToRight(); if (key.equals(HORIZONTAL_LEADING)) { key = isLeftToRight ? HORIZONTAL_LEFT : HORIZONTAL_RIGHT; } else if (key.equals(HORIZONTAL_TRAILING)) { key = isLeftToRight ? HORIZONTAL_RIGHT : HORIZONTAL_LEFT; } if (key.equals(HORIZONTAL_LEFT)) { return _hLeft; } else if (key.equals(HORIZONTAL_RIGHT)) { return _hRight; } else if (key.equals(VERTICAL_BOTTOM)) { return _vBottom; } else if (key.equals(VERTICAL_TOP)) { return _vTop; } else { return null; } } /** * Adds a child that will appear in one of the scroll bars corners. Scroll bar will make room to show the corner * component. Legal values for the key are:
  • {@link JideScrollPane#HORIZONTAL_LEFT}
  • {@link * JideScrollPane#HORIZONTAL_RIGHT}
  • {@link JideScrollPane#VERTICAL_TOP}
  • {@link * JideScrollPane#VERTICAL_BOTTOM}
  • {@link JideScrollPane#HORIZONTAL_LEADING}
  • {@link * JideScrollPane#HORIZONTAL_TRAILING}
*

* Although "corner" doesn't match any beans property signature, PropertyChange events are generated * with the property name set to the corner key. * * @param key identifies which corner the component will appear in * @param corner one of the following components:

  • lowerLeft
  • lowerRight
  • upperLeft
  • upperRight *
* @throws IllegalArgumentException if corner key is invalid */ public void setScrollBarCorner(String key, Component corner) { Component old; boolean isLeftToRight = getComponentOrientation().isLeftToRight(); if (key.equals(HORIZONTAL_LEADING)) { key = isLeftToRight ? HORIZONTAL_LEFT : HORIZONTAL_RIGHT; } else if (key.equals(HORIZONTAL_TRAILING)) { key = isLeftToRight ? HORIZONTAL_RIGHT : HORIZONTAL_LEFT; } if (key.equals(HORIZONTAL_LEFT)) { old = _hLeft; _hLeft = corner; } else if (key.equals(HORIZONTAL_RIGHT)) { old = _hRight; _hRight = corner; } else if (key.equals(VERTICAL_TOP)) { old = _vTop; _vTop = corner; } else if (key.equals(VERTICAL_BOTTOM)) { old = _vBottom; _vBottom = corner; } else { throw new IllegalArgumentException("invalid scroll bar corner key"); } if (null != old) { remove(old); } if (null != corner) { add(corner, key); } if (corner != null) corner.setComponentOrientation(getComponentOrientation()); firePropertyChange(key, old, corner); revalidate(); repaint(); } @Override public void updateUI() { super.updateUI(); setLayout(new JideScrollPaneLayout.UIResource()); if (getBorder() instanceof UIResource) { LookAndFeel.installBorder(this, "JideScrollPane.border"); } } @Override public void setLayout(LayoutManager layout) { if (!(layout instanceof JideScrollPaneLayout)) { super.setLayout(new JideScrollPaneLayout.UIResource()); } else { super.setLayout(layout); } } public boolean isVerticalScrollBarCoversWholeHeight() { return _verticalScrollBarCoversWholeHeight; } public void setHorizontalScrollBarCoversWholeWidth(boolean horizontalScrollBarCoversWholeWidth) { boolean old = _horizontalScrollBarCoversWholeWidth; if (old != horizontalScrollBarCoversWholeWidth) { _horizontalScrollBarCoversWholeWidth = horizontalScrollBarCoversWholeWidth; firePropertyChange(PROPERTY_HORIZONTAL_SCROLL_BAR_COVERS_WHOLE_WIDTH, old, _horizontalScrollBarCoversWholeWidth); invalidate(); doLayout(); if (getHorizontalScrollBar() != null) { getHorizontalScrollBar().doLayout(); } } } public boolean isHorizontalScrollBarCoversWholeWidth() { return _horizontalScrollBarCoversWholeWidth; } public void setVerticalScrollBarCoversWholeHeight(boolean verticalScrollBarCoversWholeHeight) { boolean old = _verticalScrollBarCoversWholeHeight; if (old != verticalScrollBarCoversWholeHeight) { _verticalScrollBarCoversWholeHeight = verticalScrollBarCoversWholeHeight; firePropertyChange(PROPERTY_VERTICAL_SCROLL_BAR_COVERS_WHOLE_HEIGHT, old, _verticalScrollBarCoversWholeHeight); invalidate(); doLayout(); if (getVerticalScrollBar() != null) { getVerticalScrollBar().doLayout(); } } } /** * If true, the top-right, top-left corners the column header will have the same height. If false, three of them * will keep their own preferred height. * * @return true or false. */ public boolean isColumnHeadersHeightUnified() { return _columnHeadersHeightUnified; } /** * Sets the flag if the top-right, top-left corner and the column header will have the same height or different * heights. * * @param columnHeadersHeightUnified true or false. */ public void setColumnHeadersHeightUnified(boolean columnHeadersHeightUnified) { boolean old = _columnHeadersHeightUnified; if (old != columnHeadersHeightUnified) { _columnHeadersHeightUnified = columnHeadersHeightUnified; firePropertyChange(PROPERTY_COLUMN_HEADERS_HEIGHT_UNIFIED, old, _horizontalScrollBarCoversWholeWidth); invalidate(); doLayout(); } } /** * If true, the bottom-right, bottom-left corners the column footer will have the same height. If false, three of * them will keep their own preferred height. * * @return true or false. */ public boolean isColumnFootersHeightUnified() { return _columnFootersHeightUnified; } /** * Sets the flag if the bottom-right, bottom-left corner and the column footer will have the same height or * different heights. * * @param columnFootersHeightUnified true or false. */ public void setColumnFootersHeightUnified(boolean columnFootersHeightUnified) { boolean old = _columnFootersHeightUnified; if (old != columnFootersHeightUnified) { _columnFootersHeightUnified = columnFootersHeightUnified; firePropertyChange(PROPERTY_COLUMN_FOOTERS_HEIGHT_UNIFIED, old, _horizontalScrollBarCoversWholeWidth); invalidate(); doLayout(); } } /** * Get the flag indicating if JideScrollPane should keep the corner visible when it has corner components defined * even when the scroll bar is not visible. *

* This flag will take effect only when the scroll bar policy is HORIZONTAL_SCROLLBAR_AS_NEEDED or * VERTICAL_SCROLLBAR_AS_NEEDED *

* The default value of this flag is false. * * @return the flag. */ public boolean isKeepCornerVisible() { return _keepCornerVisible; } /** * Set the flag indicating if JideScrollPane should keep the corner visible when it has corner components defined * even when the scroll bar is not visible. * * @param keepCornerVisible the flag */ public void setKeepCornerVisible(boolean keepCornerVisible) { if (_keepCornerVisible != keepCornerVisible) { boolean old = _keepCornerVisible; _keepCornerVisible = keepCornerVisible; firePropertyChange(PROPERTY_KEEP_CORNER_VISIBLE, old, _keepCornerVisible); invalidate(); doLayout(); } } /** * Gets the flag indicating if the JideScrollPane will layout its view flat without scroll bars. * * @return true if flat layout. Otherwise false. * @see #setFlatLayout(boolean) * @since 3.3.3 */ public boolean isFlatLayout() { return _flatLayout; } /** * Sets the flag indicating if the JideScrollPane will layout its view flat without scroll bars. *

* By default, the value is false to keep normal behavior. * * @param flatLayout the flag * @since 3.3.3 */ public void setFlatLayout(boolean flatLayout) { if (_flatLayout != flatLayout) { boolean old = _flatLayout; _flatLayout = flatLayout; firePropertyChange(PROPERTY_FLAT_LAYOUT, old, _flatLayout); invalidate(); doLayout(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy