
org.pushingpixels.flamingo.internal.ui.common.BasicScrollablePanelUI Maven / Gradle / Ivy
/*
* Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Flamingo Kirill Grouchnikov nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.flamingo.internal.ui.common;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import org.pushingpixels.flamingo.api.common.JCommandButton;
import org.pushingpixels.flamingo.api.common.JScrollablePanel;
import org.pushingpixels.flamingo.api.common.JScrollablePanel.ScrollType;
import org.pushingpixels.flamingo.internal.utils.DoubleArrowResizableIcon;
/**
* Basic UI for scrollable panel {@link JScrollablePanel}.
*
* @author Kirill Grouchnikov
*/
public class BasicScrollablePanelUI extends ScrollablePanelUI {
/**
* The associated scrollable panel.
*/
protected JScrollablePanel scrollablePanel;
private JPanel viewport;
private JCommandButton leadingScroller;
private JCommandButton trailingScroller;
private int viewOffset;
private MouseWheelListener mouseWheelListener;
private PropertyChangeListener propertyChangeListener;
private ComponentListener componentListener;
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
*/
public static ComponentUI createUI(JComponent c) {
return new BasicScrollablePanelUI();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#installUI(javax.swing.JComponent)
*/
@Override
public void installUI(JComponent c) {
this.scrollablePanel = (JScrollablePanel) c;
super.installUI(this.scrollablePanel);
installDefaults();
installComponents();
installListeners();
}
protected void installListeners() {
this.mouseWheelListener = new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (scrollablePanel.getScrollType() != JScrollablePanel.ScrollType.VERTICALLY) {
return;
}
int scrollAmount = 8 * e.getScrollAmount()
* e.getWheelRotation();
viewOffset += scrollAmount;
syncScrolling();
}
};
this.scrollablePanel.addMouseWheelListener(this.mouseWheelListener);
this.propertyChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("scrollOnRollover".equals(evt.getPropertyName())) {
boolean isScrollOnRollover = (Boolean) evt.getNewValue();
leadingScroller.setFireActionOnRollover(isScrollOnRollover);
trailingScroller
.setFireActionOnRollover(isScrollOnRollover);
}
}
};
this.scrollablePanel
.addPropertyChangeListener(this.propertyChangeListener);
if (this.scrollablePanel.getView() != null) {
this.componentListener = new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
scrollablePanel.doLayout();
}
};
this.scrollablePanel.getView().addComponentListener(
this.componentListener);
}
}
protected void installComponents() {
this.viewport = new JPanel(new LayoutManager() {
@Override
public void addLayoutComponent(String name, Component comp) {
}
@Override
public void removeLayoutComponent(Component comp) {
}
@Override
public Dimension preferredLayoutSize(Container parent) {
return new Dimension(10, 10);
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
@Override
public void layoutContainer(Container parent) {
JComponent view = scrollablePanel.getView();
if (scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY) {
int viewWidth = view.getPreferredSize().width;
int availWidth = parent.getWidth();
int offsetX = -viewOffset;
view.setBounds(offsetX, 0, Math.max(viewWidth, availWidth),
parent.getHeight());
} else {
int viewHeight = view.getPreferredSize().height;
int availHeight = parent.getHeight();
int offsetY = -viewOffset;
view.setBounds(0, offsetY, parent.getWidth(), Math.max(
viewHeight, availHeight));
}
}
});
JComponent view = scrollablePanel.getView();
if (view != null) {
this.viewport.add(view);
}
this.scrollablePanel.add(this.viewport);
this.leadingScroller = this.createLeadingScroller();
this.configureLeftScrollerButtonAction();
this.scrollablePanel.add(this.leadingScroller);
this.trailingScroller = this.createTrailingScroller();
this.configureRightScrollerButtonAction();
this.scrollablePanel.add(this.trailingScroller);
}
protected void installDefaults() {
this.scrollablePanel.setLayout(new ScrollablePanelLayout());
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#uninstallUI(javax.swing.JComponent)
*/
@Override
public void uninstallUI(JComponent c) {
uninstallListeners();
uninstallComponents();
uninstallDefaults();
super.uninstallUI(this.scrollablePanel);
}
protected void uninstallDefaults() {
}
protected void uninstallComponents() {
this.scrollablePanel.remove(this.viewport);
this.scrollablePanel.remove(this.leadingScroller);
this.scrollablePanel.remove(this.trailingScroller);
}
protected void uninstallListeners() {
this.scrollablePanel
.removePropertyChangeListener(this.propertyChangeListener);
this.propertyChangeListener = null;
this.scrollablePanel.removeMouseWheelListener(this.mouseWheelListener);
this.mouseWheelListener = null;
if (this.scrollablePanel.getView() != null) {
this.scrollablePanel.getView().removeComponentListener(
this.componentListener);
this.componentListener = null;
}
}
protected JCommandButton createLeadingScroller() {
JCommandButton b = new JCommandButton(
null,
new DoubleArrowResizableIcon(
new Dimension(9, 9),
this.scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY ? SwingConstants.WEST
: SwingConstants.NORTH));
b.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
b.setFocusable(false);
b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
b.putClientProperty(BasicCommandButtonUI.EMULATE_SQUARE_BUTTON,
Boolean.TRUE);
b.putClientProperty(BasicCommandButtonUI.DONT_DISPOSE_POPUPS,
Boolean.TRUE);
return b;
}
protected JCommandButton createTrailingScroller() {
JCommandButton b = new JCommandButton(
null,
new DoubleArrowResizableIcon(
new Dimension(9, 9),
this.scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY ? SwingConstants.EAST
: SwingConstants.SOUTH));
b.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
b.setFocusable(false);
b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
b.putClientProperty(BasicCommandButtonUI.EMULATE_SQUARE_BUTTON,
Boolean.TRUE);
b.putClientProperty(BasicCommandButtonUI.DONT_DISPOSE_POPUPS,
Boolean.TRUE);
return b;
}
private void syncScrolling() {
this.scrollablePanel.doLayout();
}
public void removeScrollers() {
if (this.leadingScroller.getParent() == this.scrollablePanel) {
this.scrollablePanel.remove(this.leadingScroller);
this.scrollablePanel.remove(this.trailingScroller);
syncScrolling();
this.scrollablePanel.revalidate();
this.scrollablePanel.repaint();
}
}
private void addScrollers() {
this.scrollablePanel.add(this.leadingScroller);
this.scrollablePanel.add(this.trailingScroller);
this.scrollablePanel.revalidate();
JComponent view = this.scrollablePanel.getView();
view.setPreferredSize(view.getMinimumSize());
view.setSize(view.getMinimumSize());
this.scrollablePanel.doLayout();
this.scrollablePanel.repaint();
}
protected void configureLeftScrollerButtonAction() {
this.leadingScroller.setAutoRepeatAction(true);
this.leadingScroller.setAutoRepeatActionIntervals(200, 50);
this.leadingScroller.setFireActionOnRollover(this.scrollablePanel
.isScrollOnRollover());
this.leadingScroller.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
viewOffset -= 12;
syncScrolling();
}
});
}
protected void configureRightScrollerButtonAction() {
this.trailingScroller.setAutoRepeatAction(true);
this.trailingScroller.setAutoRepeatActionIntervals(200, 50);
this.trailingScroller.setFireActionOnRollover(this.scrollablePanel
.isScrollOnRollover());
this.trailingScroller.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
viewOffset += 12;
syncScrolling();
}
});
}
@Override
public void scrollToIfNecessary(int startPosition, int span) {
if (this.scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY) {
if (this.scrollablePanel.getComponentOrientation().isLeftToRight()) {
revealRightEdge(startPosition, span);
revealLeftEdge(startPosition);
} else {
revealLeftEdge(startPosition);
revealRightEdge(startPosition, span);
}
} else {
revealBottomEdge(startPosition, span);
revealTopEdge(startPosition);
}
}
private void revealLeftEdge(int x) {
if (x < viewOffset) {
// left edge is not visible
viewOffset = x - 5;
syncScrolling();
}
}
private void revealRightEdge(int x, int width) {
if ((x + width) > (viewOffset + viewport.getWidth())) {
// right edge is not visible
viewOffset = x + width - viewport.getWidth() + 5;
syncScrolling();
}
}
private void revealTopEdge(int y) {
if (y < viewOffset) {
// top edge is not visible
viewOffset = y - 5;
syncScrolling();
}
}
private void revealBottomEdge(int y, int height) {
if ((y + height) > (viewOffset + viewport.getHeight())) {
// bottom edge is not visible
viewOffset = y + height - viewport.getHeight() + 5;
syncScrolling();
}
}
@Override
public boolean isShowingScrollButtons() {
return (this.leadingScroller.isVisible());
}
/**
* Layout for the scrollable panel.
*
* @author Kirill Grouchnikov
* @author Topologi
*/
protected class ScrollablePanelLayout implements LayoutManager {
/**
* Creates new layout manager.
*/
public ScrollablePanelLayout() {
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#addLayoutComponent(java.lang.String,
* java.awt.Component)
*/
@Override
public void addLayoutComponent(String name, Component c) {
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
*/
@Override
public void removeLayoutComponent(Component c) {
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
*/
@Override
public Dimension preferredLayoutSize(Container c) {
if (scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY) {
return new Dimension(c.getWidth(), 21);
} else {
return new Dimension(21, c.getHeight());
}
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
*/
@Override
public Dimension minimumLayoutSize(Container c) {
if (scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY) {
return new Dimension(10, 21);
} else {
return new Dimension(21, 10);
}
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
*/
@Override
public void layoutContainer(Container c) {
int width = c.getWidth();
int height = c.getHeight();
Insets ins = c.getInsets();
JComponent view = scrollablePanel.getView();
Dimension viewPrefSize = view.getPreferredSize();
// System.out.println(width + "*" + height + " - "
// + viewPrefSize.width + "*" + viewPrefSize.height);
if (scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY) {
boolean shouldShowScrollerButtons = (viewPrefSize.width > width);
leadingScroller.setVisible(shouldShowScrollerButtons);
trailingScroller.setVisible(shouldShowScrollerButtons);
int scrollPanelWidth = shouldShowScrollerButtons ? width
- ins.left - ins.right
- leadingScroller.getPreferredSize().width
- trailingScroller.getPreferredSize().width - 4 : width
- ins.left - ins.right;
int x = ins.left;
if (shouldShowScrollerButtons) {
int spw = leadingScroller.getPreferredSize().width;
leadingScroller.setBounds(x, ins.top, spw, height - ins.top
- ins.bottom);
x += spw + 2;
}
viewport.setBounds(x, ins.top, scrollPanelWidth, height
- ins.top - ins.bottom);
int viewPreferredWidth = view.getPreferredSize().width;
if (viewOffset < 0) {
viewOffset = 0;
}
if ((viewPreferredWidth > 0)
&& (viewOffset + scrollPanelWidth > viewPreferredWidth)) {
viewOffset = Math.max(0, viewPreferredWidth
- scrollPanelWidth);
}
viewport.doLayout();
x += scrollPanelWidth + 2;
if (shouldShowScrollerButtons) {
int spw = trailingScroller.getPreferredSize().width;
trailingScroller.setBounds(x, ins.top, spw, height
- ins.top - ins.bottom);
}
} else {
boolean shouldShowScrollerButtons = (viewPrefSize.height > height);
leadingScroller.setVisible(shouldShowScrollerButtons);
trailingScroller.setVisible(shouldShowScrollerButtons);
int scrollPanelHeight = shouldShowScrollerButtons ? height
- ins.top - ins.bottom
- leadingScroller.getPreferredSize().height
- trailingScroller.getPreferredSize().height - 4
: height - ins.top - ins.bottom;
int y = ins.top;
if (shouldShowScrollerButtons) {
int sph = leadingScroller.getPreferredSize().height;
leadingScroller.setBounds(ins.left, y, width - ins.left
- ins.right, sph);
y += sph + 2;
}
viewport.setBounds(ins.left, y, width - ins.left - ins.right,
scrollPanelHeight);
int viewPreferredHeight = view.getPreferredSize().height;
if (viewOffset < 0) {
viewOffset = 0;
}
if ((viewPreferredHeight > 0)
&& (viewOffset + scrollPanelHeight > viewPreferredHeight)) {
viewOffset = Math.max(0, viewPreferredHeight
- scrollPanelHeight);
}
viewport.doLayout();
y += scrollPanelHeight + 2;
if (shouldShowScrollerButtons) {
int sph = trailingScroller.getPreferredSize().height;
trailingScroller.setBounds(ins.left, y, width - ins.left
- ins.right, sph);
}
}
if (scrollablePanel.getScrollType() == ScrollType.HORIZONTALLY) {
trailingScroller
.setEnabled((viewOffset + viewport.getWidth()) < view
.getWidth());
} else {
trailingScroller
.setEnabled((viewOffset + viewport.getHeight()) < view
.getHeight());
}
leadingScroller.setEnabled(viewOffset > 0);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy