001: /*
002: * Copyright (C) 2004 NNL Technology AB
003: * Visit www.infonode.net for information about InfoNode(R)
004: * products and how to contact NNL Technology AB.
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
019: * MA 02111-1307, USA.
020: */
021:
022: //$Id: ScrollableBox.java,v 1.27 2005/12/04 13:46:04 jesper Exp $
023: package net.infonode.gui;
024:
025: import net.infonode.gui.layout.LayoutUtil;
026: import net.infonode.gui.panel.SimplePanel;
027:
028: import javax.swing.*;
029: import java.awt.*;
030: import java.awt.event.HierarchyEvent;
031: import java.awt.event.HierarchyListener;
032: import java.awt.event.MouseWheelEvent;
033: import java.awt.event.MouseWheelListener;
034: import java.util.ArrayList;
035:
036: public class ScrollableBox extends SimplePanel {
037: private LayoutManager l = new LayoutManager() {
038: public void addLayoutComponent(String name, Component comp) {
039: }
040:
041: public void layoutContainer(Container parent) {
042: if (parent.getComponentCount() > 0) {
043: Component panel = parent.getComponent(0);
044:
045: panel.setBounds(0, 0, panel.getPreferredSize().width,
046: panel.getPreferredSize().height);
047: panel.validate();
048: update();
049: }
050: }
051:
052: public Dimension minimumLayoutSize(Container parent) {
053: Dimension min = (parent.getComponentCount() == 0) ? new Dimension(
054: 0, 0)
055: : parent.getComponent(0).getMinimumSize();
056:
057: return LayoutUtil.add(
058: vertical ? new Dimension(min.width, 0)
059: : new Dimension(0, min.height), parent
060: .getInsets());
061: }
062:
063: public Dimension preferredLayoutSize(Container parent) {
064: return (parent.getComponentCount() == 0) ? new Dimension(0,
065: 0) : parent.getComponent(0).getPreferredSize();
066: }
067:
068: public void removeLayoutComponent(Component comp) {
069: }
070: };
071:
072: private int leftIndex;
073: private boolean vertical;
074: private int scrollOffset;
075:
076: private boolean leftEnd = true;
077: private boolean rightEnd = false;
078:
079: private ArrayList layoutOrderList;
080:
081: private MouseWheelListener mouseWheelListener = new MouseWheelListener() {
082: public void mouseWheelMoved(MouseWheelEvent e) {
083: setLeftIndex(leftIndex + e.getWheelRotation());
084: }
085: };
086:
087: private ArrayList listeners = new ArrayList(1);
088:
089: public ScrollableBox(final JComponent scrollingContainer,
090: boolean vertical, int scrollOffset) {
091: setLayout(l);
092: this .vertical = vertical;
093: this .scrollOffset = scrollOffset;
094: add(scrollingContainer);
095:
096: scrollingContainer.addMouseWheelListener(mouseWheelListener);
097: scrollingContainer
098: .addHierarchyListener(new HierarchyListener() {
099: public void hierarchyChanged(HierarchyEvent e) {
100: if (scrollingContainer.getParent() != ScrollableBox.this ) {
101: scrollingContainer
102: .removeHierarchyListener(this );
103: scrollingContainer
104: .removeMouseWheelListener(mouseWheelListener);
105: }
106: }
107: });
108: }
109:
110: public void addScrollableBoxListener(ScrollableBoxListener listener) {
111: listeners.add(listener);
112: }
113:
114: public void removeScrollableBoxListener(
115: ScrollableBoxListener listener) {
116: listeners.remove(listener);
117: }
118:
119: public void setScrollingContainer(final JComponent component) {
120: }
121:
122: public JComponent getScrollingComponent() {
123: return (getComponentCount() == 0) ? null
124: : (JComponent) getComponent(0);
125: }
126:
127: public void scrollLeft(int numIndex) {
128: setLeftIndex(leftIndex - numIndex);
129: }
130:
131: public void scrollRight(int numIndex) {
132: setLeftIndex(leftIndex + numIndex);
133: }
134:
135: public void ensureVisible(int index) {
136: if (leftIndex > index) {
137: setLeftIndex(index);
138: } else if (leftIndex < index) {
139: int newLeftIndex = findFitIndex(index);
140:
141: if (newLeftIndex > leftIndex) {
142: setLeftIndex(newLeftIndex);
143: }
144: }
145: }
146:
147: public boolean isLeftEnd() {
148: return leftEnd;
149: }
150:
151: public boolean isRightEnd() {
152: return rightEnd;
153: }
154:
155: public void setScrollOffset(int scrollOffset) {
156: if (scrollOffset != this .scrollOffset) {
157: this .scrollOffset = scrollOffset;
158: update();
159: }
160: }
161:
162: public int getScrollOffset() {
163: return scrollOffset;
164: }
165:
166: public boolean isVertical() {
167: return vertical;
168: }
169:
170: public void setVertical(boolean vertical) {
171: this .vertical = vertical;
172: update();
173: fireChanged();
174: }
175:
176: public void setLayoutOrderList(ArrayList layoutOrderList) {
177: this .layoutOrderList = layoutOrderList;
178: }
179:
180: private int getDimensionSize(Dimension d) {
181: return (int) (vertical ? d.getHeight() : d.getWidth());
182: }
183:
184: private Point createPos(int p) {
185: return vertical ? new Point(0, p) : new Point(p, 0);
186: }
187:
188: private int getPos(Point p) {
189: return vertical ? p.y : p.x;
190: }
191:
192: private int getScrollOffset(int index) {
193: if (index == 0)
194: return 0;
195:
196: Component c = getScrollingComponents()[index - 1];
197: return Math.min(scrollOffset, Math.max(getDimensionSize(c
198: .getMinimumSize()), getDimensionSize(c
199: .getPreferredSize()) / 2));
200: }
201:
202: private Component[] getScrollingComponents() {
203: JComponent c = getScrollingComponent();
204:
205: if (c == null)
206: return new Component[0];
207:
208: if (layoutOrderList != null) {
209: Component[] components = new Component[layoutOrderList
210: .size()];
211: for (int i = 0; i < layoutOrderList.size(); i++)
212: components[i] = (Component) layoutOrderList.get(i);
213:
214: return components;
215: }
216:
217: return c.getComponents();
218: }
219:
220: private int getScrollingComponentCount() {
221: JComponent c = getScrollingComponent();
222:
223: return (c == null) ? 0 : c.getComponentCount();
224: }
225:
226: private int findFitIndex(int lastIndex) {
227: int fitSize = getDimensionSize(getSize());
228:
229: if ((fitSize == 0) || (lastIndex < 0)) {
230: return 0;
231: }
232:
233: Component[] c = getScrollingComponents();
234: int endPos = getPos(c[lastIndex].getLocation())
235: + getDimensionSize(c[lastIndex].getSize());
236:
237: for (int i = lastIndex; i >= 0; i--) {
238: if ((endPos - getPos(c[i].getLocation()) + getScrollOffset(i)) > fitSize) {
239: return Math.min(c.length - 1, i + 1);
240: }
241: }
242:
243: return 0;
244: }
245:
246: private void update() {
247: setLeftIndex(leftIndex);
248: }
249:
250: private void setLeftIndex(int index) {
251: JComponent scrollingComponent = getScrollingComponent();
252:
253: int oldLeftIndex = leftIndex;
254:
255: if (scrollingComponent != null) {
256: int count = getScrollingComponentCount();
257: int fitIndex = findFitIndex(count - 1);
258: leftIndex = Math.min(fitIndex, Math.max(0, index));
259:
260: leftEnd = leftIndex == 0;
261: rightEnd = !(leftIndex < fitIndex);
262:
263: scrollingComponent.setLocation(createPos(((count == 0) ? 0
264: : (-getPos(getScrollingComponents()[leftIndex]
265: .getLocation())))
266: + getScrollOffset(leftIndex)));
267: Object[] l = listeners.toArray();
268: for (int i = 0; i < l.length; i++)
269: if (oldLeftIndex < index)
270: fireScrolledRight();
271: else if (oldLeftIndex > index)
272: fireScrolledLeft();
273: }
274: }
275:
276: public void updateUI() {
277: super .updateUI();
278: if (listeners != null)
279: fireChanged();
280: }
281:
282: private void fireScrolledLeft() {
283: Object[] l = listeners.toArray();
284: for (int i = 0; i < l.length; i++)
285: ((ScrollableBoxListener) l[i]).scrolledLeft(this );
286: }
287:
288: private void fireScrolledRight() {
289: Object[] l = listeners.toArray();
290: for (int i = 0; i < l.length; i++)
291: ((ScrollableBoxListener) l[i]).scrolledRight(this );
292: }
293:
294: private void fireChanged() {
295: Object[] l = listeners.toArray();
296: for (int i = 0; i < l.length; i++)
297: ((ScrollableBoxListener) l[i]).changed(this);
298: }
299: }
|