001: /*
002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of Substance Kirill Grouchnikov nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030: package org.jvnet.substance;
031:
032: import java.awt.*;
033: import java.awt.event.*;
034: import java.awt.geom.Area;
035: import java.beans.PropertyChangeEvent;
036: import java.beans.PropertyChangeListener;
037: import java.util.*;
038:
039: import javax.swing.*;
040: import javax.swing.border.Border;
041: import javax.swing.event.ChangeEvent;
042: import javax.swing.event.ChangeListener;
043: import javax.swing.plaf.ComponentUI;
044: import javax.swing.plaf.UIResource;
045: import javax.swing.plaf.basic.BasicScrollPaneUI;
046: import javax.swing.table.JTableHeader;
047:
048: import org.jvnet.lafwidget.LafWidgetUtilities;
049: import org.jvnet.lafwidget.animation.*;
050: import org.jvnet.lafwidget.layout.TransitionBorder;
051: import org.jvnet.lafwidget.layout.TransitionLayout;
052: import org.jvnet.lafwidget.utils.LafConstants;
053: import org.jvnet.substance.scroll.SubstanceScrollPaneBorder;
054: import org.jvnet.substance.utils.SubstanceCoreUtilities;
055: import org.jvnet.substance.utils.SubstanceSizeUtils;
056:
057: /**
058: * UI for scroll panes in <b>Substance</b> look and feel.
059: *
060: * @author Kirill Grouchnikov
061: */
062: public class SubstanceScrollPaneUI extends BasicScrollPaneUI {
063: /**
064: * Property change listener on
065: * {@link SubstanceLookAndFeel#SCROLL_PANE_BUTTONS_POLICY},
066: * {@link SubstanceLookAndFeel#WATERMARK_TO_BLEED} and
067: * <code>layoutManager</code> properties.
068: */
069: protected PropertyChangeListener substancePropertyChangeListener;
070:
071: /**
072: * Listener on the vertical scroll bar. Installed for the smart tree scroll
073: * (see {@link SubstanceLookAndFeel#TREE_SMART_SCROLL_ANIMATION_KIND}.
074: */
075: protected ChangeListener substanceVerticalScrollbarChangeListener;
076:
077: /**
078: * Fade ID of the current horizontal scroll under smart tree scroll mode.
079: */
080: protected long horScrollId;
081:
082: /**
083: * Background delegate.
084: */
085: protected static SubstanceFillBackgroundDelegate bgDelegate = new SubstanceFillBackgroundDelegate();
086:
087: /**
088: * Creates new UI delegate.
089: *
090: * @param c
091: * Component.
092: * @return UI delegate for the component.
093: */
094: public static ComponentUI createUI(JComponent c) {
095: return new SubstanceScrollPaneUI();
096: }
097:
098: /*
099: * (non-Javadoc)
100: *
101: * @see javax.swing.plaf.basic.BasicScrollPaneUI#installDefaults(javax.swing.JScrollPane)
102: */
103: @Override
104: protected void installDefaults(final JScrollPane scrollpane) {
105: super .installDefaults(scrollpane);
106: if (SubstanceCoreUtilities.toBleedWatermark(scrollpane)) {
107: scrollpane.setOpaque(false);
108: scrollpane.getViewport().setOpaque(false);
109: }
110: scrollpane.setLayout(new AdjustedLayout(
111: (ScrollPaneLayout) scrollpane.getLayout()));
112:
113: SwingUtilities.invokeLater(new Runnable() {
114: public void run() {
115: installTableHeaderCornerFiller(scrollpane);
116: }
117: });
118: }
119:
120: /*
121: * (non-Javadoc)
122: *
123: * @see javax.swing.plaf.basic.BasicScrollPaneUI#uninstallDefaults(javax.swing.JScrollPane)
124: */
125: @Override
126: protected void uninstallDefaults(JScrollPane c) {
127: Component upperRight = c
128: .getCorner(JScrollPane.UPPER_RIGHT_CORNER);
129: if (upperRight instanceof UIResource) {
130: c.setCorner(JScrollPane.UPPER_RIGHT_CORNER, null);
131: }
132: Component upperLeft = c
133: .getCorner(JScrollPane.UPPER_LEFT_CORNER);
134: if (upperLeft instanceof UIResource) {
135: c.setCorner(JScrollPane.UPPER_LEFT_CORNER, null);
136: }
137:
138: LayoutManager lm = scrollpane.getLayout();
139: if (lm instanceof AdjustedLayout) {
140: c.setLayout(((AdjustedLayout) lm).delegate);
141: }
142: super .uninstallDefaults(c);
143: }
144:
145: // /*
146: // * (non-Javadoc)
147: // *
148: // * @see
149: // javax.swing.plaf.basic.BasicScrollPaneUI#uninstallDefaults(javax.swing.JScrollPane)
150: // */
151: // @Override
152: // protected void uninstallDefaults(JScrollPane c) {
153: // super.uninstallDefaults(c);
154: // ScrollPaneSelector.uninstallScrollPaneSelector(scrollpane);
155: // }
156: //
157: /*
158: * (non-Javadoc)
159: *
160: * @see javax.swing.plaf.basic.BasicScrollPaneUI#installListeners(javax.swing.JScrollPane)
161: */
162: @Override
163: protected void installListeners(final JScrollPane c) {
164: super .installListeners(c);
165: this .substancePropertyChangeListener = new PropertyChangeListener() {
166: public void propertyChange(PropertyChangeEvent evt) {
167: if (SubstanceLookAndFeel.SCROLL_PANE_BUTTONS_POLICY
168: .equals(evt.getPropertyName())) {
169: SwingUtilities.invokeLater(new Runnable() {
170: public void run() {
171: c.getHorizontalScrollBar().doLayout();
172: c.getVerticalScrollBar().doLayout();
173: }
174: });
175: }
176: if (SubstanceLookAndFeel.WATERMARK_TO_BLEED.equals(evt
177: .getPropertyName())) {
178: boolean toBleed = SubstanceCoreUtilities
179: .toBleedWatermark(c);
180: c.setOpaque(!toBleed);
181: c.getViewport().setOpaque(!toBleed);
182: Component view = c.getViewport().getView();
183: if (view instanceof JComponent)
184: ((JComponent) view).setOpaque(!toBleed);
185: }
186: if ("layoutManager".equals(evt.getPropertyName())) {
187: if (((Boolean) evt.getNewValue()).booleanValue()) {
188: ScrollPaneLayout currLayout = (ScrollPaneLayout) c
189: .getLayout();
190: if (!(currLayout instanceof AdjustedLayout)) {
191: c.setLayout(new AdjustedLayout(
192: (ScrollPaneLayout) c.getLayout()));
193: }
194: }
195: // else {
196: // ScrollPaneLayout currLayout = (ScrollPaneLayout) c
197: // .getLayout();
198: // if (currLayout instanceof AdjustedLayout) {
199: // c.setLayout(((AdjustedLayout) currLayout).delegate);
200: // }
201: // }
202: }
203: if ("background".equals(evt.getPropertyName())) {
204: // propagate application-specific background color to the
205: // scroll bars.
206: Color newBackgr = (Color) evt.getNewValue();
207: if (!(newBackgr instanceof UIResource)) {
208: JScrollBar vertical = scrollpane
209: .getVerticalScrollBar();
210: if (vertical != null) {
211: if (vertical.getBackground() instanceof UIResource) {
212: vertical.setBackground(newBackgr);
213: }
214: }
215: JScrollBar horizontal = scrollpane
216: .getHorizontalScrollBar();
217: if (horizontal != null) {
218: if (horizontal.getBackground() instanceof UIResource) {
219: horizontal.setBackground(newBackgr);
220: }
221: }
222: }
223: }
224: if ("columnHeader".equals(evt.getPropertyName())) {
225: SwingUtilities.invokeLater(new Runnable() {
226: public void run() {
227: // need to switch the corner filler based on the
228: // header
229: if (scrollpane != null) {
230: installTableHeaderCornerFiller(scrollpane);
231: }
232: }
233: });
234: }
235: if ("componentOrientation"
236: .equals(evt.getPropertyName())) {
237: SwingUtilities.invokeLater(new Runnable() {
238: public void run() {
239: // need to switch the corner filler based on the
240: // component orientation
241: if (scrollpane != null) {
242: installTableHeaderCornerFiller(scrollpane);
243: }
244: }
245: });
246: }
247: }
248: };
249: c
250: .addPropertyChangeListener(this .substancePropertyChangeListener);
251:
252: this .substanceVerticalScrollbarChangeListener = new ChangeListener() {
253: public void stateChanged(ChangeEvent e) {
254: // check if it's a tree inside
255: if (c.getViewport().getView() instanceof JTree) {
256: JTree tree = (JTree) c.getViewport().getView();
257: // check if the smart scroll is enabled
258: if (FadeConfigurationManager
259: .getInstance()
260: .fadeAllowed(
261: SubstanceLookAndFeel.TREE_SMART_SCROLL_ANIMATION_KIND,
262: tree)) {
263: SubstanceTreeUI treeUI = (SubstanceTreeUI) tree
264: .getUI();
265: final Rectangle viewportRect = c.getViewport()
266: .getViewRect();
267: int pivotX = treeUI
268: .getPivotRendererX(viewportRect);
269: int currPivotX = viewportRect.x;// + viewportRect.width
270: // / 2;
271: int delta = pivotX - currPivotX;
272: int finalX = viewportRect.x + delta;
273: if (finalX < 0) {
274: delta -= finalX;
275: }
276: final int finalDelta = delta;
277: if (Math.abs(finalDelta) > viewportRect.width / 6) {
278: // System.err.println("Median : " + medianX);
279: FadeTrackerCallback callback = new EDTFadeTrackerAdapter() {
280: @Override
281: public void fadeEnded(FadeKind fadeKind) {
282: // nothing to do here - the scroll has been
283: // either cancelled or just ended
284: }
285:
286: @Override
287: public void fadePerformed(
288: FadeKind fadeKind,
289: float fadeCycle10) {
290: if (fadeCycle10 >= 5.0) {
291: int nudge = (int) (finalDelta
292: * (fadeCycle10 - 5.0) / 5.0);
293: c
294: .getViewport()
295: .setViewPosition(
296: new Point(
297: viewportRect.x
298: + nudge,
299: viewportRect.y));
300: }
301: // System.out.println(fadeCycle10);
302: }
303: };
304: // synchronized (SubstanceScrollPaneUI.this) {
305: if (horScrollId >= 0) {
306: // cancel previous horizontal scroll
307: // synchronized (SubstanceScrollPaneUI.this) {
308: // System.err.println("Cancelling " +
309: // horScrollId);
310: FadeTracker
311: .getInstance()
312: .cancelFadeInstance(horScrollId);
313: // }
314: }
315: final FadeStep delegate = LafWidgetUtilities
316: .getAnimationKind(tree).getStep();
317: horScrollId = FadeTracker
318: .getInstance()
319: .trackFadeIn(
320: SubstanceLookAndFeel.TREE_SMART_SCROLL_ANIMATION_KIND,
321: tree,
322: null,
323: false,
324: callback,
325: new LafConstants.AnimationKind(
326: new FadeStep() {
327: public float getNextStep(
328: FadeKind fadeKind,
329: float currFadePosition,
330: boolean isFadeIn,
331: boolean isLooping) {
332: if (currFadePosition < 0.5)
333: return delegate
334: .getNextStep(
335: fadeKind,
336: currFadePosition,
337: isFadeIn,
338: isLooping) / 3.0f;
339: else
340: return delegate
341: .getNextStep(
342: fadeKind,
343: currFadePosition,
344: isFadeIn,
345: isLooping) / 1.5f;
346: }
347: },
348: "substancelaf.treeSmartScrollFadeStep"));
349:
350: // }
351: // System.err.println("Starting " + horScrollId);
352: }
353: }
354: }
355: }
356: };
357: c.getVerticalScrollBar().getModel().addChangeListener(
358: this .substanceVerticalScrollbarChangeListener);
359: }
360:
361: /*
362: * (non-Javadoc)
363: *
364: * @see javax.swing.plaf.basic.BasicScrollPaneUI#uninstallListeners(javax.swing.JComponent)
365: */
366: @Override
367: protected void uninstallListeners(JComponent c) {
368: c
369: .removePropertyChangeListener(this .substancePropertyChangeListener);
370: this .substancePropertyChangeListener = null;
371:
372: JScrollPane jsp = (JScrollPane) c;
373: jsp.getVerticalScrollBar().getModel().removeChangeListener(
374: this .substanceVerticalScrollbarChangeListener);
375: this .substanceVerticalScrollbarChangeListener = null;
376:
377: super .uninstallListeners(c);
378: }
379:
380: /*
381: * (non-Javadoc)
382: *
383: * @see javax.swing.plaf.basic.BasicScrollPaneUI#createMouseWheelListener()
384: */
385: @Override
386: protected MouseWheelListener createMouseWheelListener() {
387: return new MouseWheelHandler();
388: }
389:
390: /**
391: * Custom mouse wheel handler. Provides faster scrolling - issue 87.
392: *
393: * @author Kirill Grouchnikov
394: */
395: protected class MouseWheelHandler implements MouseWheelListener {
396: /*
397: * (non-Javadoc)
398: *
399: * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
400: */
401: public void mouseWheelMoved(java.awt.event.MouseWheelEvent e) {
402: if (SubstanceScrollPaneUI.this .scrollpane
403: .isWheelScrollingEnabled()
404: && (e.getScrollAmount() != 0)) {
405: JScrollBar toScroll = SubstanceScrollPaneUI.this .scrollpane
406: .getVerticalScrollBar();
407: int direction = 0;
408:
409: // find which scrollbar to scroll, or return if none
410: if ((toScroll == null) || !toScroll.isVisible()
411: || (e.getModifiers() == InputEvent.ALT_MASK)) {
412: toScroll = SubstanceScrollPaneUI.this .scrollpane
413: .getHorizontalScrollBar();
414:
415: if ((toScroll == null) || !toScroll.isVisible()) {
416: return;
417: }
418: }
419:
420: direction = (e.getWheelRotation() < 0) ? (-1) : 1;
421:
422: SubstanceScrollBarUI ui = (SubstanceScrollBarUI) toScroll
423: .getUI();
424: if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
425: ui
426: .scrollByUnits(direction, 2 * e
427: .getScrollAmount());
428: } else if (e.getScrollType() == MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
429: ui.scrollByBlock(direction);
430: }
431: }
432: }
433: }
434:
435: /**
436: * Layout manager to adjust the bounds of scrollbars and the viewport when
437: * the default ({@link SubstanceScrollPaneBorder}) border is set on the
438: * relevant {@link JScrollPane}.
439: *
440: * @author Kirill Grouchnikov
441: */
442: protected static class AdjustedLayout extends ScrollPaneLayout
443: implements UIResource {
444: /**
445: * The delegate layout.
446: */
447: protected ScrollPaneLayout delegate;
448:
449: /**
450: * Creates a new layout for adjusting the bounds of scrollbars and the
451: * viewport.
452: *
453: * @param delegate
454: * The original (delegate) layout.
455: */
456: public AdjustedLayout(ScrollPaneLayout delegate) {
457: this .delegate = delegate;
458: }
459:
460: @Override
461: public void addLayoutComponent(String s, Component c) {
462: delegate.addLayoutComponent(s, c);
463: }
464:
465: @Override
466: public boolean equals(Object obj) {
467: return delegate.equals(obj);
468: }
469:
470: @Override
471: public JViewport getColumnHeader() {
472: return delegate.getColumnHeader();
473: }
474:
475: @Override
476: public Component getCorner(String key) {
477: return delegate.getCorner(key);
478: }
479:
480: @Override
481: public JScrollBar getHorizontalScrollBar() {
482: return delegate.getHorizontalScrollBar();
483: }
484:
485: @Override
486: public int getHorizontalScrollBarPolicy() {
487: return delegate.getHorizontalScrollBarPolicy();
488: }
489:
490: @Override
491: public JViewport getRowHeader() {
492: return delegate.getRowHeader();
493: }
494:
495: @Override
496: public JScrollBar getVerticalScrollBar() {
497: return delegate.getVerticalScrollBar();
498: }
499:
500: @Override
501: public int getVerticalScrollBarPolicy() {
502: return delegate.getVerticalScrollBarPolicy();
503: }
504:
505: @Override
506: public JViewport getViewport() {
507: return delegate.getViewport();
508: }
509:
510: @Override
511: @SuppressWarnings("deprecation")
512: public Rectangle getViewportBorderBounds(JScrollPane scrollpane) {
513: return delegate.getViewportBorderBounds(scrollpane);
514: }
515:
516: @Override
517: public int hashCode() {
518: return delegate.hashCode();
519: }
520:
521: @Override
522: public Dimension minimumLayoutSize(Container parent) {
523: return delegate.minimumLayoutSize(parent);
524: }
525:
526: @Override
527: public Dimension preferredLayoutSize(Container parent) {
528: return delegate.preferredLayoutSize(parent);
529: }
530:
531: @Override
532: public void removeLayoutComponent(Component c) {
533: delegate.removeLayoutComponent(c);
534: }
535:
536: @Override
537: public void setHorizontalScrollBarPolicy(int x) {
538: delegate.setHorizontalScrollBarPolicy(x);
539: }
540:
541: @Override
542: public void setVerticalScrollBarPolicy(int x) {
543: delegate.setVerticalScrollBarPolicy(x);
544: }
545:
546: @Override
547: public void syncWithScrollPane(JScrollPane sp) {
548: delegate.syncWithScrollPane(sp);
549: }
550:
551: @Override
552: public String toString() {
553: return delegate.toString();
554: }
555:
556: // ScrollPaneLayout.UIResource {
557: /*
558: * (non-Javadoc)
559: *
560: * @see javax.swing.ScrollPaneLayout#layoutContainer(java.awt.Container)
561: */
562: @Override
563: public void layoutContainer(Container parent) {
564: delegate.layoutContainer(parent);
565:
566: JScrollPane scrollPane = (JScrollPane) parent;
567: Border border = scrollPane.getBorder();
568: boolean toAdjust = (border instanceof SubstanceScrollPaneBorder);
569: if (border instanceof TransitionBorder) {
570: toAdjust = (((TransitionBorder) border).getDelegate() instanceof SubstanceScrollPaneBorder);
571: }
572: if (toAdjust) {
573: JScrollBar vertical = scrollPane.getVerticalScrollBar();
574: JScrollBar horizontal = scrollPane
575: .getHorizontalScrollBar();
576:
577: int borderDelta = (int) Math
578: .floor(SubstanceSizeUtils
579: .getBorderStrokeWidth(SubstanceSizeUtils
580: .getComponentFontSize(scrollPane)) / 2.0);
581: int borderWidth = (int) SubstanceSizeUtils
582: .getBorderStrokeWidth(SubstanceSizeUtils
583: .getComponentFontSize(scrollPane));
584: int dx = 0, dy = 0, dw = 0, dh = 0;
585: if (scrollPane.getComponentOrientation()
586: .isLeftToRight()) {
587: if (vertical.isVisible()) {
588: Rectangle vBounds = vertical.getBounds();
589: dw += (1 + borderDelta);
590: vertical.setBounds(vBounds.x + 1 + borderDelta,
591: vBounds.y + 1 - 2 * borderWidth,
592: vBounds.width, vBounds.height + 2
593: * borderWidth);
594: }
595: if (horizontal.isVisible()) {
596: dh += (1 + borderDelta);
597: Rectangle hBounds = horizontal.getBounds();
598: horizontal.setBounds(hBounds.x + 1 - 2
599: * borderWidth, hBounds.y + 1,
600: hBounds.width + 2 * borderWidth,
601: hBounds.height);
602: }
603:
604: if (delegate
605: .getCorner(ScrollPaneLayout.LOWER_RIGHT_CORNER) != null) {
606: Rectangle lrBounds = delegate.getCorner(
607: ScrollPaneLayout.LOWER_RIGHT_CORNER)
608: .getBounds();
609: delegate
610: .getCorner(
611: ScrollPaneLayout.LOWER_RIGHT_CORNER)
612: .setBounds(
613: lrBounds.x + 1 + borderDelta,
614: lrBounds.y + 1 + borderDelta,
615: lrBounds.width, lrBounds.height);
616: }
617: if (delegate
618: .getCorner(ScrollPaneLayout.UPPER_RIGHT_CORNER) != null) {
619: Rectangle urBounds = delegate.getCorner(
620: ScrollPaneLayout.UPPER_RIGHT_CORNER)
621: .getBounds();
622: delegate.getCorner(
623: ScrollPaneLayout.UPPER_RIGHT_CORNER)
624: .setBounds(
625: urBounds.x + 1 + borderDelta,
626: urBounds.y + borderDelta,
627: urBounds.width - 1,
628: urBounds.height);
629: }
630: } else {
631: if (vertical.isVisible()) {
632: dx -= (1 + borderDelta);
633: dw += (1 + borderDelta);
634: Rectangle vBounds = vertical.getBounds();
635: vertical.setBounds(vBounds.x - 1 - borderDelta,
636: vBounds.y - 1 - borderDelta,
637: vBounds.width, vBounds.height + 2
638: * borderWidth);
639: }
640: if (horizontal.isVisible()) {
641: dh += (1 + borderDelta);
642: Rectangle hBounds = horizontal.getBounds();
643: horizontal.setBounds(hBounds.x - 1
644: - borderDelta, hBounds.y + 1
645: + borderDelta, hBounds.width + 2
646: * borderWidth, hBounds.height);
647: }
648: if (delegate
649: .getCorner(ScrollPaneLayout.LOWER_LEFT_CORNER) != null) {
650: Rectangle llBounds = delegate.getCorner(
651: ScrollPaneLayout.LOWER_LEFT_CORNER)
652: .getBounds();
653: delegate
654: .getCorner(
655: ScrollPaneLayout.LOWER_LEFT_CORNER)
656: .setBounds(
657: llBounds.x - 1 - borderDelta,
658: llBounds.y - 1 - borderDelta,
659: llBounds.width, llBounds.height);
660: }
661: if (delegate
662: .getCorner(ScrollPaneLayout.UPPER_LEFT_CORNER) != null) {
663: Rectangle ulBounds = delegate.getCorner(
664: ScrollPaneLayout.UPPER_LEFT_CORNER)
665: .getBounds();
666: delegate.getCorner(
667: ScrollPaneLayout.UPPER_LEFT_CORNER)
668: .setBounds(ulBounds.x - borderDelta,
669: ulBounds.y - borderDelta,
670: ulBounds.width - 1,
671: ulBounds.height);
672: }
673: }
674:
675: if (delegate.getViewport() != null) {
676: Rectangle vpBounds = delegate.getViewport()
677: .getBounds();
678: delegate.getViewport().setBounds(
679: new Rectangle(vpBounds.x + dx, vpBounds.y
680: + dy, vpBounds.width + dw,
681: vpBounds.height + dh));
682: }
683: if (delegate.getColumnHeader() != null) {
684: Rectangle columnHeaderBounds = delegate
685: .getColumnHeader().getBounds();
686: delegate.getColumnHeader().setBounds(
687: new Rectangle(columnHeaderBounds.x + dx,
688: columnHeaderBounds.y + dy,
689: columnHeaderBounds.width + dw,
690: columnHeaderBounds.height));
691: }
692: }
693: }
694: }
695:
696: /*
697: * (non-Javadoc)
698: *
699: * @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
700: * javax.swing.JComponent)
701: */
702: @Override
703: public void update(Graphics g, JComponent c) {
704: bgDelegate.updateIfOpaque(g, c);
705: JScrollPane jsp = (JScrollPane) c;
706: if (SubstanceCoreUtilities.hasOverlayProperty(jsp)) {
707: JViewport viewport = jsp.getViewport();
708: int dx = -viewport.getX() + viewport.getViewRect().x;
709: int dy = viewport.getY() - viewport.getViewRect().y;
710: Graphics2D graphics = (Graphics2D) g.create();
711:
712: Area clip = new Area();
713: if ((jsp.getVerticalScrollBar() != null)
714: && jsp.getVerticalScrollBar().isVisible())
715: clip.add(new Area(jsp.getVerticalScrollBar()
716: .getBounds()));
717: if ((jsp.getHorizontalScrollBar() != null)
718: && jsp.getHorizontalScrollBar().isVisible())
719: clip.add(new Area(jsp.getHorizontalScrollBar()
720: .getBounds()));
721: graphics.setClip(clip);
722:
723: graphics.translate(-dx, dy);
724: JComponent view = (JComponent) viewport.getView();
725: // fix for defect 201 - set non-double buffer for the viewport
726: // recursively. Takes care of desktop pane wrapped in scroll pane.
727: Map<Component, Boolean> dbSnapshot = new HashMap<Component, Boolean>();
728: SubstanceCoreUtilities.makeNonDoubleBuffered(view,
729: dbSnapshot);
730: view.paint(graphics);
731: // restore the double buffer.
732: SubstanceCoreUtilities.restoreDoubleBuffered(view,
733: dbSnapshot);
734: graphics.translate(dx, -dy);
735: graphics.dispose();
736: }
737:
738: LayoutManager lm = jsp.getLayout();
739: ScrollPaneLayout scrollLm = null;
740: if (lm instanceof ScrollPaneLayout) {
741: scrollLm = (ScrollPaneLayout) lm;
742: } else {
743: if (lm instanceof TransitionLayout) {
744: LayoutManager origLm = ((TransitionLayout) lm)
745: .getDelegate();
746: if (origLm instanceof ScrollPaneLayout) {
747: scrollLm = (ScrollPaneLayout) origLm;
748: }
749: }
750: }
751:
752: if (scrollLm != null) {
753: Set<Component> corners = new HashSet<Component>();
754: if (scrollLm.getCorner(ScrollPaneLayout.LOWER_LEFT_CORNER) != null) {
755: corners.add(scrollLm
756: .getCorner(ScrollPaneLayout.LOWER_LEFT_CORNER));
757: }
758: if (scrollLm.getCorner(ScrollPaneLayout.LOWER_RIGHT_CORNER) != null) {
759: corners
760: .add(scrollLm
761: .getCorner(ScrollPaneLayout.LOWER_RIGHT_CORNER));
762: }
763: if (scrollLm.getCorner(ScrollPaneLayout.UPPER_LEFT_CORNER) != null) {
764: corners.add(scrollLm
765: .getCorner(ScrollPaneLayout.UPPER_LEFT_CORNER));
766: }
767: if (scrollLm.getCorner(ScrollPaneLayout.UPPER_RIGHT_CORNER) != null) {
768: corners
769: .add(scrollLm
770: .getCorner(ScrollPaneLayout.UPPER_RIGHT_CORNER));
771: }
772:
773: if (TransitionLayout.isOpaque(c)) {
774: for (Component corner : corners) {
775: bgDelegate.fillAndWatermark(g, c,
776: c.getBackground(), corner.getBounds());
777: }
778: }
779: }
780:
781: super .paint(g, c);
782: }
783:
784: protected static void installTableHeaderCornerFiller(
785: JScrollPane scrollpane) {
786: // install custom scroll pane corner filler
787: // for continuous painting of table headers
788: JViewport columnHeader = scrollpane.getColumnHeader();
789: if (columnHeader == null)
790: return;
791: Component columnHeaderComp = columnHeader.getView();
792: if (!(columnHeaderComp instanceof JTableHeader))
793: return;
794: JTableHeader tableHeader = (JTableHeader) columnHeaderComp;
795: SubstanceTableHeaderUI ui = (SubstanceTableHeaderUI) tableHeader
796: .getUI();
797: JComponent scrollPaneCornerFiller = ui
798: .getScrollPaneCornerFiller();
799: // System.err.println("Installed " + scrollPaneCornerFiller.hashCode()
800: // + " on " + scrollpane.hashCode());
801: String cornerKey = scrollpane.getComponentOrientation()
802: .isLeftToRight() ? JScrollPane.UPPER_RIGHT_CORNER
803: : JScrollPane.UPPER_LEFT_CORNER;
804: Component cornerComp = scrollpane.getCorner(cornerKey);
805: if ((cornerComp != null)
806: && (!(cornerComp instanceof UIResource))) {
807: // can't replace
808: return;
809: }
810: scrollpane.setCorner(cornerKey, scrollPaneCornerFiller);
811: }
812: }
|