001: package org.netbeans.modules.bpel.design;
002:
003: import java.awt.BorderLayout;
004: import java.awt.Color;
005: import java.awt.Component;
006: import java.awt.Dimension;
007: import java.awt.Graphics;
008: import java.awt.Graphics2D;
009: import java.awt.Insets;
010: import java.awt.Point;
011: import java.awt.Rectangle;
012: import java.awt.RenderingHints;
013: import java.awt.Shape;
014: import java.awt.event.ActionEvent;
015: import java.awt.event.ActionListener;
016: import java.awt.event.MouseWheelEvent;
017: import java.awt.event.MouseWheelListener;
018: import java.awt.geom.GeneralPath;
019: import java.util.ArrayList;
020: import javax.swing.ButtonModel;
021: import javax.swing.JButton;
022: import javax.swing.JComponent;
023: import javax.swing.JPanel;
024: import javax.swing.JScrollBar;
025: import javax.swing.JScrollPane;
026: import javax.swing.JViewport;
027: import javax.swing.Timer;
028: import javax.swing.border.Border;
029: import javax.swing.event.ChangeEvent;
030: import javax.swing.event.ChangeListener;
031:
032: /**
033: *
034: * @author anjeleevich
035: */
036: public class TriScrollPane extends JScrollPane {
037:
038: private JComponent left;
039: private JComponent right;
040: private JComponent center;
041: private JComponent handToolPanel;
042: private JComponent overlayPanel;
043: private SideComponent leftComponent;
044: private SideComponent rightComponent;
045: private boolean layoutNow = false;
046: private ArrayList<ScrollListener> scrollListeners = new ArrayList<ScrollListener>(
047: 1);
048:
049: public TriScrollPane(JComponent center, JComponent left,
050: JComponent right, JComponent handToolPanel,
051: JComponent overlayPanel) {
052: super (center);
053:
054: setBorder(null);
055:
056: this .handToolPanel = handToolPanel;
057: this .overlayPanel = overlayPanel;
058:
059: this .left = left;
060: this .right = right;
061: this .center = center;
062:
063: leftComponent = new SideComponent(left);
064: leftComponent.setBorder(LEFT_SIDE_BORDER);
065:
066: rightComponent = new SideComponent(right);
067: rightComponent.setBorder(RIGHT_SIDE_BORDER);
068:
069: add(leftComponent);
070: add(rightComponent);
071:
072: if (overlayPanel != null) {
073: add(overlayPanel, 0);
074: }
075:
076: if (handToolPanel != null) {
077: add(handToolPanel, 0);
078: }
079:
080: getVerticalScrollBar().setUnitIncrement(10);
081: getHorizontalScrollBar().setUnitIncrement(10);
082: getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
083:
084: getViewport().addChangeListener(myScrollListener);
085: leftComponent.getViewport().addChangeListener(myScrollListener);
086: rightComponent.getViewport()
087: .addChangeListener(myScrollListener);
088: }
089:
090: public void addScrollListener(ScrollListener l) {
091: scrollListeners.add(l);
092: }
093:
094: public void removeScrollListener(ScrollListener l) {
095: scrollListeners.remove(l);
096: }
097:
098: public int getWidth() {
099: if (layoutNow) {
100: int leftWidth = (!left.isVisible()) ? 0 : leftComponent
101: .getPreferredSize().width;
102: int rightWidth = (!right.isVisible()) ? 0 : rightComponent
103: .getPreferredSize().width;
104:
105: return super .getWidth() - leftWidth - rightWidth;
106: }
107:
108: return super .getWidth();
109: }
110:
111: public Rectangle getBounds() {
112: return new Rectangle(getX(), getY(), getWidth(), getHeight());
113: }
114:
115: public void doLayout() {
116: layoutNow = true;
117: super .doLayout();
118: layoutNow = false;
119:
120: boolean leftVisible = left.isVisible();
121: boolean rightVisible = right.isVisible();
122:
123: int leftWidth = (!leftVisible) ? 0 : leftComponent
124: .getPreferredSize().width;
125: int rightWidth = (!rightVisible) ? 0 : rightComponent
126: .getPreferredSize().width;
127:
128: JScrollBar vsb = getVerticalScrollBar();
129: JScrollBar hsb = getHorizontalScrollBar();
130:
131: Rectangle viewportBounds = getViewport().getBounds();
132:
133: if (handToolPanel != null) {
134: handToolPanel.setBounds(viewportBounds.x, viewportBounds.y,
135: leftWidth + viewportBounds.width + rightWidth,
136: viewportBounds.height);
137: }
138:
139: if (overlayPanel != null) {
140: overlayPanel.setBounds(viewportBounds.x, viewportBounds.y,
141: leftWidth + viewportBounds.width + rightWidth,
142: viewportBounds.height);
143: }
144:
145: Rectangle vsbBounds = (vsb.isVisible()) ? vsb.getBounds()
146: : null;
147: Rectangle hsbBounds = (hsb.isVisible()) ? hsb.getBounds()
148: : null;
149:
150: int vsbOffset = leftWidth + rightWidth;
151:
152: if (leftWidth != 0) {
153: viewportBounds.x += leftWidth;
154: viewport.setBounds(viewportBounds);
155: }
156:
157: if (vsbOffset != 0) {
158: if (vsbBounds != null) {
159: vsbBounds.x += vsbOffset;
160: vsb.setBounds(vsbBounds);
161: }
162:
163: if (hsbBounds != null) {
164: hsbBounds.width += vsbOffset;
165: hsb.setBounds(hsbBounds);
166: }
167: }
168:
169: if (leftVisible) {
170: leftComponent.setVisible(true);
171: leftComponent.setBounds(viewportBounds.x - leftWidth,
172: viewportBounds.y, leftWidth, viewportBounds.height);
173: }
174:
175: if (rightVisible) {
176: rightComponent.setVisible(true);
177: rightComponent.setBounds(viewportBounds.x
178: + viewportBounds.width, viewportBounds.y,
179: rightWidth, viewportBounds.height);
180: }
181: }
182:
183: public JComponent getComponent(Point pt) {
184: if (rightComponent.getBounds().contains(pt)) {
185: return right;
186: } else if (viewport.getBounds().contains(pt)) {
187: return center;
188: } else if (leftComponent.getBounds().contains(pt)) {
189: return left;
190: } else {
191: return null;
192: }
193: }
194:
195: public Dimension getPreferredSize() {
196: Dimension size = super .getPreferredSize();
197:
198: boolean leftVisible = left.isVisible();
199: boolean rightVisible = right.isVisible();
200:
201: int leftWidth = (!left.isVisible()) ? 0 : leftComponent
202: .getPreferredSize().width;
203: int rightWidth = (!right.isVisible()) ? 0 : rightComponent
204: .getPreferredSize().width;
205:
206: size.width += leftWidth + rightWidth;
207:
208: return size;
209: }
210:
211: private static class SideComponent extends JPanel implements
212: ChangeListener, MouseWheelListener, ActionListener {
213:
214: JButton scrollUpButton;
215: JButton scrollDownButton;
216: JScrollPane scrollPane;
217: Timer scrollTimer;
218: int scrollTimerDirection = 0;
219:
220: SideComponent(JComponent content) {
221: scrollPane = new JScrollPane(content,
222: JScrollPane.VERTICAL_SCROLLBAR_NEVER,
223: JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
224: scrollPane.setBorder(null);
225: scrollPane.getViewport().setScrollMode(
226: JViewport.SIMPLE_SCROLL_MODE);
227: scrollUpButton = new UpButton();
228: scrollDownButton = new DownButton();
229:
230: add(scrollUpButton, BorderLayout.NORTH);
231: add(scrollDownButton, BorderLayout.SOUTH);
232: add(scrollPane, BorderLayout.CENTER);
233:
234: scrollPane.getViewport().addChangeListener(this );
235: scrollPane.addMouseWheelListener(this );
236: scrollUpButton.getModel().addChangeListener(this );
237: scrollDownButton.getModel().addChangeListener(this );
238:
239: scrollTimer = new Timer(100, this );
240: }
241:
242: public JViewport getViewport() {
243: return scrollPane.getViewport();
244: }
245:
246: public Dimension getPreferredSize() {
247: Insets insets = getInsets();
248:
249: Dimension size = scrollPane.getPreferredSize();
250:
251: int w = Math.max(size.width, BUTTON_SIZE + BUTTON_PADDING
252: * 2);
253: int h = Math.max(size.height, 2 * BUTTON_SIZE
254: + BUTTON_PADDING * 2 + BUTTON_MARGIN);
255:
256: size.width = w + insets.left + insets.right;
257: size.height = h + insets.top + insets.bottom;
258:
259: return size;
260: }
261:
262: public void doLayout() {
263: int w = getWidth();
264: int h = getHeight();
265:
266: Insets insets = getInsets();
267:
268: int x = insets.left;
269: int y = insets.top;
270:
271: w -= insets.left + insets.right;
272: h -= insets.top + insets.bottom;
273:
274: scrollPane.setBounds(x, y, w, h);
275:
276: int buttonX = x + (w - BUTTON_SIZE) / 2;
277:
278: scrollUpButton.setBounds(buttonX, y + BUTTON_PADDING,
279: BUTTON_SIZE, BUTTON_SIZE);
280:
281: scrollDownButton.setBounds(buttonX, y + h - BUTTON_SIZE
282: - BUTTON_PADDING, BUTTON_SIZE, BUTTON_SIZE);
283:
284: updateButtonsVisibility();
285: }
286:
287: private void updateButtonsVisibility() {
288: JViewport viewport = scrollPane.getViewport();
289:
290: Rectangle viewRect = viewport.getViewRect();
291: Dimension viewSize = viewport.getViewSize();
292:
293: scrollUpButton.setVisible(viewRect.y > 0);
294: scrollDownButton
295: .setVisible(viewRect.y + viewRect.height < viewSize.height);
296: }
297:
298: private void scroll(int scrollUnits) {
299: if (scrollUnits == 0) {
300: return;
301: }
302:
303: int delta = scrollUnits * 10;
304:
305: JViewport viewport = scrollPane.getViewport();
306:
307: Point viewPosition = viewport.getViewPosition();
308:
309: int yMax = viewport.getViewSize().height
310: - viewport.getExtentSize().height;
311:
312: viewPosition.y = Math.max(0, Math.min(viewPosition.y
313: + delta, yMax));
314:
315: viewport.setViewPosition(viewPosition);
316: }
317:
318: public boolean isOptimizedDrawingEnabled() {
319: return false;
320: }
321:
322: public void stateChanged(ChangeEvent e) {
323: if (e.getSource() == scrollPane.getViewport()) {
324: updateButtonsVisibility();
325: } else if (e.getSource() == scrollUpButton.getModel()) {
326: if (scrollUpButton.getModel().isPressed()) {
327: scrollTimerDirection = -3;
328: scroll(scrollTimerDirection);
329: scrollTimer.restart();
330: } else {
331: scrollTimer.stop();
332: }
333: } else if (e.getSource() == scrollDownButton.getModel()) {
334: if (scrollDownButton.getModel().isPressed()) {
335: scrollTimerDirection = 3;
336: scroll(scrollTimerDirection);
337: scrollTimer.restart();
338: } else {
339: scrollTimer.stop();
340: }
341: }
342: }
343:
344: public void mouseWheelMoved(MouseWheelEvent e) {
345: scroll(e.getUnitsToScroll());
346: }
347:
348: public void actionPerformed(ActionEvent e) {
349: scroll(scrollTimerDirection);
350: }
351: }
352:
353: private abstract static class ScrollButton extends JButton {
354:
355: ScrollButton() {
356: setContentAreaFilled(false);
357: setRolloverEnabled(true);
358: setBorderPainted(false);
359: setOpaque(false);
360: setFocusable(false);
361: }
362:
363: public boolean contains(int x, int y) {
364: double rx = 0.5 * getWidth();
365: double ry = 0.5 * getHeight();
366:
367: double px = x - rx;
368: double py = y - ry;
369:
370: return px * px / rx / rx + py * py / ry / ry <= 1.0;
371: }
372:
373: public void paintComponent(Graphics g) {
374: int w = getWidth();
375: int h = getHeight();
376:
377: Graphics2D g2 = (Graphics2D) g.create();
378: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
379: RenderingHints.VALUE_ANTIALIAS_ON);
380: g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
381: RenderingHints.VALUE_STROKE_PURE);
382:
383: ButtonModel model = getModel();
384: Shape icon = createIconShape();
385:
386: if (model.isPressed()) {
387: g2.setPaint(BUTTON_PRESSED_FILL);
388: } else if (model.isRollover()) {
389: g2.setPaint(BUTTON_ROLLOVER_FILL);
390: } else {
391: g2.setPaint(BUTTON_FILL);
392: }
393: g2.translate(0.5, 0.5);
394: g2.fillOval(0, 0, w - 1, h - 1);
395: g2.translate(-0.5, -0.5);
396:
397: if (model.isRollover()) {
398: g2.setPaint(ICON_COLOR_ROLLOVER);
399: } else {
400: g2.setPaint(ICON_COLOR);
401: }
402: g2.fill(icon);
403:
404: if (model.isPressed()) {
405: g2.setPaint(BUTTON_PRESSED_STROKE);
406: } else if (model.isRollover()) {
407: g2.setPaint(BUTTON_ROLLOVER_STROKE);
408: } else {
409: g2.setPaint(BUTTON_STROKE);
410: }
411: g2.translate(0.5, 0.5);
412: g2.drawOval(0, 0, w - 1, h - 1);
413: g2.translate(-0.5, -0.5);
414: g2.draw(icon);
415:
416: g2.dispose();
417: }
418:
419: public Dimension getPreferredSize() {
420: return new Dimension(BUTTON_SIZE, BUTTON_SIZE);
421: }
422:
423: abstract Shape createIconShape();
424: }
425:
426: private static class UpButton extends ScrollButton {
427:
428: Shape createIconShape() {
429: ButtonModel model = getModel();
430:
431: float cx = 0.5f * getWidth();
432: float cy = 0.5f * getHeight();
433:
434: float r = Math.min(cx, cy) - 6.5f;
435: float x = r * COS_30;
436: float y = r * SIN_30;
437:
438: GeneralPath gp = new GeneralPath();
439: gp.moveTo(cx, cy - r);
440: gp.lineTo(cx + x, cy + y);
441: gp.lineTo(cx - x, cy + y);
442: gp.closePath();
443:
444: return gp;
445: }
446: }
447:
448: private static class DownButton extends ScrollButton {
449:
450: Shape createIconShape() {
451: ButtonModel model = getModel();
452:
453: float cx = 0.5f * getWidth();
454: float cy = 0.5f * getHeight();
455:
456: float r = -(Math.min(cx, cy) - 6.5f);
457: float x = r * COS_30;
458: float y = r * SIN_30;
459:
460: GeneralPath gp = new GeneralPath();
461: gp.moveTo(cx, cy - r);
462: gp.lineTo(cx + x, cy + y);
463: gp.lineTo(cx - x, cy + y);
464: gp.closePath();
465:
466: return gp;
467: }
468: }
469:
470: private static final Border LEFT_SIDE_BORDER = new Border() {
471:
472: public Insets getBorderInsets(Component c) {
473: return new Insets(0, 0, 0, 1);
474: }
475:
476: public boolean isBorderOpaque() {
477: return true;
478: }
479:
480: public void paintBorder(Component c, Graphics g, int x, int y,
481: int width, int height) {
482: Color oldColor = g.getColor();
483:
484: int x1 = x + width - 1;
485: int y1 = y + height - 1;
486:
487: g.setColor(c.getBackground().darker());
488: g.drawLine(x1, y, x1, y1);
489: g.setColor(oldColor);
490: }
491: };
492: private static final Border RIGHT_SIDE_BORDER = new Border() {
493:
494: public Insets getBorderInsets(Component c) {
495: return new Insets(0, 1, 0, 0);
496: }
497:
498: public boolean isBorderOpaque() {
499: return true;
500: }
501:
502: public void paintBorder(Component c, Graphics g, int x, int y,
503: int width, int height) {
504: Color oldColor = g.getColor();
505:
506: int y1 = y + height - 1;
507:
508: g.setColor(Color.LIGHT_GRAY);
509: g.drawLine(x, y, x, y1);
510: g.setColor(oldColor);
511: }
512: };
513:
514: private ChangeListener myScrollListener = new ChangeListener() {
515: public void stateChanged(ChangeEvent e) {
516: if (e.getSource() != getViewport()) {
517: center.repaint();
518: }
519:
520: for (ScrollListener l : scrollListeners) {
521: l.viewScrolled(null);
522: }
523: }
524: };
525:
526: public interface ScrollListener {
527: void viewScrolled(JComponent view);
528: }
529:
530: private static final int BUTTON_SIZE = 23;
531: private static final int BUTTON_PADDING = 4;
532: private static final int BUTTON_MARGIN = 4;
533: private static final Color BUTTON_FILL = new Color(0x88CCCCCC, true);
534: private static final Color BUTTON_STROKE = new Color(0x88888888,
535: true);
536: private static final Color BUTTON_ROLLOVER_FILL = new Color(
537: 0xCCCCCC);
538: private static final Color BUTTON_ROLLOVER_STROKE = new Color(
539: 0x888888);
540: private static final Color BUTTON_PRESSED_FILL = new Color(0xBBBBBB);
541: private static final Color BUTTON_PRESSED_STROKE = new Color(
542: 0x888888);
543: private static final Color ICON_COLOR = new Color(0x88FFFFFF, true);
544: private static final Color ICON_COLOR_ROLLOVER = new Color(0xFFFFFF);
545: private static final float COS_30 = (float) Math.cos(Math.PI / 6);
546: private static final float SIN_30 = (float) Math.sin(Math.PI / 6);
547: }
|