0001: /*
0002: * Copyright 2005-2008 Kirill Grouchnikov, based on work by
0003: * Sun Microsystems, Inc. All rights reserved.
0004: *
0005: * This library is free software; you can redistribute it and/or
0006: * modify it under the terms of the GNU Lesser General Public
0007: * License as published by the Free Software Foundation; either
0008: * version 2.1 of the License, or (at your option) any later version.
0009: *
0010: * This library is distributed in the hope that it will be useful,
0011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013: * Lesser General Public License for more details.
0014: *
0015: * You should have received a copy of the GNU Lesser General Public
0016: * License along with this library; if not, write to the Free Software
0017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
0018: */
0019: package org.jvnet.substance.swingx;
0020:
0021: import java.awt.*;
0022: import java.awt.event.*;
0023: import java.util.*;
0024:
0025: import javax.swing.*;
0026: import javax.swing.plaf.ComponentUI;
0027: import javax.swing.plaf.basic.BasicLookAndFeel;
0028:
0029: import org.jdesktop.swingx.JXMonthView;
0030: import org.jdesktop.swingx.calendar.DateSelectionModel;
0031: import org.jdesktop.swingx.event.DateSelectionEvent;
0032: import org.jdesktop.swingx.event.DateSelectionListener;
0033: import org.jdesktop.swingx.plaf.basic.BasicMonthViewUI;
0034: import org.jvnet.lafwidget.LafWidgetUtilities;
0035: import org.jvnet.lafwidget.animation.*;
0036: import org.jvnet.lafwidget.layout.TransitionLayout;
0037: import org.jvnet.substance.*;
0038: import org.jvnet.substance.painter.highlight.SubstanceHighlightUtils;
0039: import org.jvnet.substance.painter.text.SubstanceTextPainter;
0040: import org.jvnet.substance.theme.SubstanceTheme;
0041: import org.jvnet.substance.utils.*;
0042:
0043: /**
0044: * Substance-consistent UI delegate for {@link JXMonthView}.
0045: *
0046: * @author Kirill Grouchnikov
0047: */
0048: public class SubstanceMonthViewUI extends BasicMonthViewUI implements
0049: Trackable {
0050: protected int headerHeight;
0051:
0052: /**
0053: * Listener for fade animations on rollovers.
0054: */
0055: protected DayRolloverFadeListener substanceFadeRolloverListener;
0056:
0057: protected int rolloverDayId;
0058:
0059: protected int rolloverMonthId;
0060:
0061: protected int rolloverYearId;
0062:
0063: /**
0064: * Holds the list of currently selected days. Every entry is day:month:year
0065: */
0066: protected Set<String> selectedIndices;
0067:
0068: /**
0069: * Listener for fade animations on day selections.
0070: */
0071: protected DateSelectionListener substanceFadeSelectionListener;
0072:
0073: /**
0074: * Map of previous fade states (for state-aware theme transitions).
0075: */
0076: private Map<String, ComponentState> prevDayStateMap;
0077:
0078: /**
0079: * Map of next fade states (for state-aware theme transitions).
0080: */
0081: private Map<String, ComponentState> nextDayStateMap;
0082:
0083: /**
0084: * Map of previous fade states (for state-aware theme transitions).
0085: */
0086: private Map<String, ComponentState> prevMonthStateMap;
0087:
0088: /**
0089: * Map of next fade states (for state-aware theme transitions).
0090: */
0091: private Map<String, ComponentState> nextMonthStateMap;
0092:
0093: public static ComponentUI createUI(JComponent c) {
0094: return new SubstanceMonthViewUI();
0095: }
0096:
0097: /**
0098: * Creates a new UI delegate.
0099: */
0100: public SubstanceMonthViewUI() {
0101: super ();
0102:
0103: this .prevDayStateMap = new HashMap<String, ComponentState>();
0104: this .nextDayStateMap = new HashMap<String, ComponentState>();
0105: this .prevMonthStateMap = new HashMap<String, ComponentState>();
0106: this .nextMonthStateMap = new HashMap<String, ComponentState>();
0107:
0108: this .selectedIndices = new HashSet<String>();
0109:
0110: this .rolloverDayId = -1;
0111: this .rolloverMonthId = -1;
0112: this .rolloverYearId = -1;
0113: }
0114:
0115: /*
0116: * (non-Javadoc)
0117: *
0118: * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installDefaults()
0119: */
0120: @Override
0121: protected void installDefaults() {
0122: super .installDefaults();
0123: this .monthDownImage = SubstanceImageCreator.getArrowIcon(
0124: this .monthView.getFont().getSize(),
0125: SwingConstants.WEST, SubstanceThemeUtilities.getTheme(
0126: this .monthView, ComponentState.ACTIVE));
0127: this .monthUpImage = SubstanceImageCreator.getArrowIcon(
0128: this .monthView.getFont().getSize(),
0129: SwingConstants.EAST, SubstanceThemeUtilities.getTheme(
0130: this .monthView, ComponentState.ACTIVE));
0131: BasicLookAndFeel.installColors(this .monthView,
0132: "JXMonthView.background", "JXMonthView.foreground");
0133:
0134: Calendar cal = this .monthView.getCalendar();
0135: if (cal != null) {
0136: for (Date selected : this .getSelection()) {
0137: cal.setTime(selected);
0138: int day = cal.get(Calendar.DAY_OF_MONTH);
0139: int month = cal.get(Calendar.MONTH);
0140: int year = cal.get(Calendar.YEAR);
0141: this .selectedIndices
0142: .add(day + ":" + month + ":" + year);
0143: }
0144: }
0145: }
0146:
0147: /*
0148: * (non-Javadoc)
0149: *
0150: * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installListeners()
0151: */
0152: @Override
0153: protected void installListeners() {
0154: super .installListeners();
0155:
0156: this .substanceFadeRolloverListener = new DayRolloverFadeListener();
0157: this .monthView
0158: .addMouseMotionListener(substanceFadeRolloverListener);
0159: this .monthView.addMouseListener(substanceFadeRolloverListener);
0160:
0161: // Add listener for the selection animation
0162: substanceFadeSelectionListener = new DateSelectionListener() {
0163: protected void cancelFades(Set<Long> initiatedFadeSequences) {
0164: FadeTracker fadeTrackerInstance = FadeTracker
0165: .getInstance();
0166: for (long fadeId : initiatedFadeSequences) {
0167: fadeTrackerInstance.cancelFadeInstance(fadeId);
0168: }
0169: }
0170:
0171: public void valueChanged(DateSelectionEvent ev) {
0172: if (LafWidgetUtilities.hasNoFades(monthView,
0173: FadeKind.SELECTION))
0174: return;
0175:
0176: Set<Long> initiatedFadeSequences = new HashSet<Long>();
0177: boolean fadeCanceled = false;
0178:
0179: Calendar cal = monthView.getCalendar();
0180:
0181: cal.set(Calendar.DAY_OF_MONTH, 1);
0182: int month = cal.get(Calendar.MONTH);
0183:
0184: DateSelectionModel selectionModel = monthView
0185: .getSelectionModel();
0186:
0187: FadeTracker fadeTrackerInstance = FadeTracker
0188: .getInstance();
0189: while (cal.get(Calendar.MONTH) == month) {
0190: int dayIndex = cal.get(Calendar.DAY_OF_MONTH);
0191: int monthIndex = cal.get(Calendar.MONTH);
0192: int yearIndex = cal.get(Calendar.YEAR);
0193: String index = dayIndex + ":" + monthIndex + ":"
0194: + yearIndex;
0195:
0196: if (selectionModel.isSelected(cal.getTime())) {
0197: // check if was selected before
0198: if (!selectedIndices.contains(dayIndex)) {
0199: // start fading in
0200: // System.out.println("Fade in on index " + i);
0201:
0202: if (!fadeCanceled) {
0203: long fadeId = fadeTrackerInstance
0204: .trackFadeIn(
0205: FadeKind.SELECTION,
0206: monthView, index,
0207: false,
0208: new DayRepaintCallback(
0209: monthView,
0210: dayIndex,
0211: monthIndex,
0212: yearIndex));
0213: initiatedFadeSequences.add(fadeId);
0214: if (initiatedFadeSequences.size() > 25) {
0215: cancelFades(initiatedFadeSequences);
0216: initiatedFadeSequences.clear();
0217: fadeCanceled = true;
0218: }
0219: }
0220:
0221: selectedIndices.add(index);
0222: }
0223: } else {
0224: // check if was selected before
0225: if (selectedIndices.contains(dayIndex)) {
0226: // start fading out
0227: // System.out.println("Fade out on index " + i);
0228:
0229: if (!fadeCanceled) {
0230: long fadeId = fadeTrackerInstance
0231: .trackFadeOut(
0232: FadeKind.SELECTION,
0233: monthView, index,
0234: false,
0235: new DayRepaintCallback(
0236: monthView,
0237: dayIndex,
0238: monthIndex,
0239: yearIndex));
0240: initiatedFadeSequences.add(fadeId);
0241: if (initiatedFadeSequences.size() > 25) {
0242: cancelFades(initiatedFadeSequences);
0243: initiatedFadeSequences.clear();
0244: fadeCanceled = true;
0245: }
0246: }
0247: selectedIndices.remove(dayIndex);
0248: }
0249: }
0250: cal.add(Calendar.DAY_OF_MONTH, 1);
0251: }
0252: }
0253: };
0254: this .monthView.getSelectionModel().addDateSelectionListener(
0255: this .substanceFadeSelectionListener);
0256: }
0257:
0258: /*
0259: * (non-Javadoc)
0260: *
0261: * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#uninstallListeners()
0262: */
0263: @Override
0264: protected void uninstallListeners() {
0265: this .monthView.getSelectionModel().removeDateSelectionListener(
0266: this .substanceFadeSelectionListener);
0267: this .substanceFadeSelectionListener = null;
0268:
0269: this .monthView
0270: .removeMouseListener(this .substanceFadeRolloverListener);
0271: this .monthView
0272: .removeMouseMotionListener(this .substanceFadeRolloverListener);
0273: this .substanceFadeRolloverListener = null;
0274:
0275: super .uninstallListeners();
0276: }
0277:
0278: /*
0279: * (non-Javadoc)
0280: *
0281: * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#uninstallDefaults()
0282: */
0283: @Override
0284: protected void uninstallDefaults() {
0285: selectedIndices.clear();
0286:
0287: super .uninstallDefaults();
0288: }
0289:
0290: @Override
0291: protected void paintMonthStringBackground(Graphics g, final int x,
0292: final int y, final int width, final int height,
0293: final Calendar cal) {
0294: this .headerHeight = height;
0295:
0296: SubstanceTextPainter textPainter = SubstanceLookAndFeel
0297: .getCurrentTextPainter();
0298: textPainter.init(this .monthView, null, true);
0299:
0300: SubstanceTextPainter.BackgroundPaintingCallback callback = new SubstanceTextPainter.BackgroundPaintingCallback() {
0301: public void paintBackground(Graphics g) {
0302: Graphics2D g2d = (Graphics2D) g.create();
0303:
0304: ComponentState componentState = monthView.isEnabled() ? ComponentState.DEFAULT
0305: : ComponentState.DISABLED_UNSELECTED;
0306: SubstanceTheme fillTheme = SubstanceThemeUtilities
0307: .getTheme(monthView, componentState);
0308: float fillAlpha = SubstanceThemeUtilities.getTheme(
0309: monthView, componentState).getThemeAlpha(
0310: monthView, componentState);
0311: g2d.setComposite(TransitionLayout.getAlphaComposite(
0312: monthView, fillAlpha, g));
0313:
0314: SubstanceHighlightUtils.paintHighlight(g2d, monthView,
0315: new Rectangle(x, y, width, height), 0.5f, null,
0316: fillTheme.getColorScheme(), fillTheme
0317: .getColorScheme(), 0.0f);
0318: g2d.setComposite(TransitionLayout.getAlphaComposite(
0319: monthView, g));
0320: // System.out.println("Fill " + fillTheme.getDisplayName()
0321: // + " at " + fillAlpha + "[" + componentState + "]");
0322:
0323: ComponentState prevState = getPrevMonthState(cal
0324: .get(Calendar.MONTH), cal.get(Calendar.YEAR));
0325: ComponentState currState = getMonthState(cal
0326: .get(Calendar.MONTH), cal.get(Calendar.YEAR));
0327: // System.out.println(cellId + ":" + prevState.name() + "->"
0328: // + currState.name());
0329:
0330: // Compute the alpha values for the animation.
0331: float startAlpha = SubstanceThemeUtilities
0332: .getHighlightAlpha(monthView, prevState);
0333: float endAlpha = SubstanceThemeUtilities
0334: .getHighlightAlpha(monthView, currState);
0335:
0336: FadeState state = SubstanceFadeUtilities.getFadeState(
0337: monthView, cal.get(Calendar.MONTH) + ":"
0338: + cal.get(Calendar.YEAR),
0339: FadeKind.ROLLOVER);
0340:
0341: float totalAlpha = endAlpha;
0342: float fadeCoef = 0.0f;
0343: if (state != null) {
0344: fadeCoef = state.getFadePosition();
0345:
0346: // compute the total alpha of the overlays.
0347: if (state.isFadingIn()) {
0348: totalAlpha = startAlpha
0349: + (endAlpha - startAlpha) * fadeCoef
0350: / 10.0f;
0351: } else {
0352: totalAlpha = startAlpha
0353: + (endAlpha - startAlpha)
0354: * (10.0f - fadeCoef) / 10.0f;
0355: }
0356:
0357: if (state.isFadingIn())
0358: fadeCoef = 10.0f - fadeCoef;
0359: }
0360:
0361: final SubstanceTheme prevTheme = SubstanceThemeUtilities
0362: .getHighlightTheme(monthView, prevState);
0363: final SubstanceTheme currTheme = SubstanceThemeUtilities
0364: .getHighlightTheme(monthView, currState);
0365:
0366: if (totalAlpha > 0.0f) {
0367: g2d
0368: .setComposite(TransitionLayout
0369: .getAlphaComposite(monthView,
0370: totalAlpha, g));
0371: SubstanceHighlightUtils.paintHighlight(g2d,
0372: monthView, new Rectangle(x, y, width,
0373: height), 0.5f, null, currTheme
0374: .getColorScheme(), prevTheme
0375: .getColorScheme(), fadeCoef);
0376: g2d.setComposite(TransitionLayout
0377: .getAlphaComposite(monthView, g));
0378: }
0379: g2d.dispose();
0380: }
0381: };
0382:
0383: if (textPainter.needsBackgroundImage()) {
0384: textPainter.attachCallback(callback);
0385: } else {
0386: callback.paintBackground(g);
0387: }
0388: }
0389:
0390: @Override
0391: protected void paintDayOfTheWeekBackground(Graphics g, int x,
0392: int y, int width, int height, Calendar cal) {
0393: int boxPaddingX = this .monthView.getBoxPaddingX();
0394:
0395: Graphics2D graphics = (Graphics2D) g.create();
0396: graphics.translate(x + boxPaddingX, y + height - 1);
0397:
0398: SubstanceTheme theme = SubstanceThemeUtilities.getTheme(
0399: this .monthView).getDefaultTheme();
0400: SubstanceCoreUtilities.paintSeparator(this .monthView, graphics,
0401: theme.getColorScheme(), SubstanceCoreUtilities
0402: .isThemeDark(theme), width, 1,
0403: JSeparator.HORIZONTAL, true, 0);
0404: graphics.dispose();
0405: }
0406:
0407: @Override
0408: protected void paintWeekOfYearBackground(Graphics g, int x, int y,
0409: int width, int height, Calendar cal) {
0410: int boxPaddingY = this .monthView.getBoxPaddingY();
0411: x = this .monthView.getComponentOrientation().isLeftToRight() ? x
0412: + width - 1
0413: : x;
0414:
0415: Graphics2D graphics = (Graphics2D) g.create();
0416: graphics.translate(x, y + boxPaddingY);
0417:
0418: SubstanceTheme theme = SubstanceThemeUtilities.getTheme(
0419: this .monthView).getDefaultTheme();
0420: SubstanceCoreUtilities.paintSeparator(this .monthView, graphics,
0421: theme.getColorScheme(), SubstanceCoreUtilities
0422: .isThemeDark(theme), 1, height,
0423: JSeparator.VERTICAL, true, 0);
0424: graphics.dispose();
0425: }
0426:
0427: /*
0428: * (non-Javadoc)
0429: *
0430: * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#paintBackground(java.awt.Rectangle,
0431: * java.awt.Graphics)
0432: */
0433: @Override
0434: protected void paintBackground(Rectangle clip, Graphics graphics) {
0435: SubstanceFillBackgroundDelegate.GLOBAL_INSTANCE.update(
0436: graphics, this .monthView, false);
0437: }
0438:
0439: /*
0440: * (non-Javadoc)
0441: *
0442: * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#paintDayBackground(java.awt.Graphics,
0443: * int, int, int, int, java.util.Calendar)
0444: */
0445: @Override
0446: protected void paintDayBackground(Graphics g, int x, int y,
0447: int width, int height, Calendar cal) {
0448: Graphics2D graphics = (Graphics2D) g.create();
0449: Rectangle area = new Rectangle(x, y, width, height);
0450: // this.bgDelegate.fillAndWatermark(graphics, this.monthView,
0451: // this.monthView.getBackground(), area);
0452:
0453: int day = cal.get(Calendar.DAY_OF_MONTH);
0454: int month = cal.get(Calendar.MONTH);
0455: int year = cal.get(Calendar.YEAR);
0456:
0457: // System.out.println(date + ":" + day + "/" + month + " - " +
0458: // this.currMonth);
0459: if (month != cal.get(Calendar.MONTH)) {
0460: // leading or trailing days
0461: return;
0462: }
0463:
0464: ComponentState prevState = getPrevDayState(day, month, year);
0465: ComponentState currState = getDayState(day, month, year);
0466:
0467: // if (prevState != ComponentState.DEFAULT
0468: // || currState != ComponentState.DEFAULT)
0469: // System.out.println(day + ":" + prevState + "->" + currState);
0470:
0471: // Compute the alpha values for the animation.
0472: float startAlpha = SubstanceThemeUtilities.getHighlightAlpha(
0473: monthView, prevState);
0474: float endAlpha = SubstanceThemeUtilities.getHighlightAlpha(
0475: monthView, currState);
0476:
0477: FadeState state = SubstanceFadeUtilities.getFadeState(
0478: monthView, day + ":" + month + ":" + year,
0479: FadeKind.SELECTION, FadeKind.ROLLOVER);
0480: float totalAlpha = endAlpha;
0481: float fadeCoef = 0.0f;
0482: if (state != null) {
0483: fadeCoef = state.getFadePosition();
0484:
0485: // compute the total alpha of the overlays.
0486: if (state.isFadingIn()) {
0487: totalAlpha = startAlpha + (endAlpha - startAlpha)
0488: * fadeCoef / 10.0f;
0489: } else {
0490: totalAlpha = startAlpha + (endAlpha - startAlpha)
0491: * (10.0f - fadeCoef) / 10.0f;
0492: }
0493:
0494: if (state.isFadingIn())
0495: fadeCoef = 10.0f - fadeCoef;
0496: }
0497:
0498: SubstanceTheme prevTheme = SubstanceThemeUtilities
0499: .getHighlightTheme(monthView, prevState);
0500: SubstanceTheme currTheme = SubstanceThemeUtilities
0501: .getHighlightTheme(monthView, currState);
0502:
0503: if (totalAlpha > 0.0f) {
0504: graphics.setComposite(TransitionLayout.getAlphaComposite(
0505: monthView, totalAlpha, g));
0506: SubstanceHighlightUtils.paintHighlight(graphics, monthView,
0507: area, 0.5f, null, currTheme.getColorScheme(),
0508: prevTheme.getColorScheme(), fadeCoef);
0509: graphics.setComposite(TransitionLayout.getAlphaComposite(
0510: monthView, g));
0511: }
0512:
0513: graphics.dispose();
0514: }
0515:
0516: @Override
0517: protected void paintDayForeground(Graphics g, String numericDay,
0518: int x, int y, Calendar cal) {
0519: Graphics2D g2d = (Graphics2D) g.create();
0520: int day = Integer.parseInt(numericDay);
0521: ComponentState state = this .getDayState(day, cal
0522: .get(Calendar.MONTH), cal.get(Calendar.YEAR));
0523: ComponentState prevState = this .getPrevDayState(day, cal
0524: .get(Calendar.MONTH), cal.get(Calendar.YEAR));
0525: Color fg = SubstanceCoreUtilities
0526: .getInterpolatedForegroundColor(this .monthView, day,
0527: SubstanceThemeUtilities.getTheme(
0528: this .monthView, state), state,
0529: prevState, FadeKind.ROLLOVER,
0530: FadeKind.SELECTION);
0531:
0532: // System.out.println(numericDay + " --> " + fg);
0533: g2d.setColor(fg);
0534: FontMetrics fm = g2d.getFontMetrics();
0535: g2d.drawString(numericDay, x - fm.stringWidth(numericDay), y
0536: + fm.getAscent());
0537:
0538: g2d.dispose();
0539: }
0540:
0541: // /*
0542: // * (non-Javadoc)
0543: // *
0544: // * @see
0545: // org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#paintMonth(java.awt.Graphics,
0546: // * int, int, int, int, java.util.Calendar)
0547: // */
0548: // @Override
0549: // protected void paintMonth(Graphics g, int x, int y, int width, int
0550: // height,
0551: // Calendar cal) {
0552: // this.monthTitleBoundsMap.put(cal.get(Calendar.MONTH) + ":"
0553: // + cal.get(Calendar.YEAR), new Rectangle(x, y, width, height));
0554: // super.paintMonth(g, x, y, width, height, cal);
0555: // }
0556: //
0557: @Override
0558: protected void paintMonthStringForeground(Graphics g,
0559: String monthName, int monthX, int monthY, String yearName,
0560: int yearX, int yearY, Calendar cal) {
0561: Graphics2D g2d = (Graphics2D) g.create();
0562: ComponentState state = getMonthState(cal.get(Calendar.MONTH),
0563: cal.get(Calendar.YEAR));
0564: ComponentState prevState = getPrevMonthState(cal
0565: .get(Calendar.MONTH), cal.get(Calendar.YEAR));
0566:
0567: Color fg = SubstanceCoreUtilities
0568: .getInterpolatedForegroundColor(this .monthView, null,
0569: SubstanceThemeUtilities.getTheme(
0570: this .monthView, state), state,
0571: prevState, FadeKind.ROLLOVER,
0572: FadeKind.SELECTION);
0573:
0574: SubstanceTextPainter textPainter = SubstanceLookAndFeel
0575: .getCurrentTextPainter();
0576: // textPainter.init(this.monthView, null, true);
0577: SubstanceCoreUtilities.paintTextWithDropShadow(this .monthView,
0578: g2d, fg, monthName, this .monthView.getWidth(),
0579: this .headerHeight, monthX, monthY);
0580: SubstanceCoreUtilities.paintTextWithDropShadow(this .monthView,
0581: g2d, fg, yearName, this .monthView.getWidth(),
0582: this .headerHeight, yearX, yearY);
0583: textPainter.renderSurface(g2d);
0584:
0585: g2d.dispose();
0586: }
0587:
0588: /*
0589: * (non-Javadoc)
0590: *
0591: * @see org.jvnet.substance.utils.Trackable#isInside(java.awt.event.MouseEvent)
0592: */
0593: public boolean isInside(MouseEvent me) {
0594: // The entire component area is considered as trackable for rollover
0595: // effects.
0596: return true;
0597: // return this.monthView.getBounds().contains(me.getPoint());
0598: }
0599:
0600: /**
0601: * Listener for fade animations on month view rollovers.
0602: *
0603: * @author Kirill Grouchnikov
0604: */
0605: private class DayRolloverFadeListener implements MouseListener,
0606: MouseMotionListener {
0607: public void mouseClicked(MouseEvent e) {
0608: }
0609:
0610: public void mouseEntered(MouseEvent e) {
0611: }
0612:
0613: public void mousePressed(MouseEvent e) {
0614: }
0615:
0616: public void mouseReleased(MouseEvent e) {
0617: }
0618:
0619: public void mouseExited(MouseEvent e) {
0620: this .fadeOutDay();
0621: this .fadeOutMonth();
0622: // System.out.println("Nulling RO index");
0623: resetRolloverIndex();
0624: }
0625:
0626: public void mouseMoved(MouseEvent e) {
0627: if (!monthView.isEnabled())
0628: return;
0629: this .handleMove(e);
0630: }
0631:
0632: public void mouseDragged(MouseEvent e) {
0633: // if (SubstanceCoreUtilities.toBleedWatermark(list))
0634: // return;
0635:
0636: if (!monthView.isEnabled())
0637: return;
0638: this .handleMove(e);
0639: }
0640:
0641: /**
0642: * Handles various mouse move events and initiates the fade animation if
0643: * necessary.
0644: *
0645: * @param e
0646: * Mouse event.
0647: */
0648: private void handleMove(MouseEvent e) {
0649: boolean fadeAllowed = FadeConfigurationManager
0650: .getInstance().fadeAllowed(FadeKind.ROLLOVER,
0651: monthView);
0652: if (!fadeAllowed) {
0653: this .fadeOutDay();
0654: this .fadeOutMonth();
0655: resetRolloverIndex();
0656: return;
0657: }
0658:
0659: Date matchingDay = monthView.getDayAtLocation(e.getX(), e
0660: .getY());
0661: if (matchingDay == null) {
0662: this .fadeOutDay();
0663: this .fadeOutMonth();
0664: // System.out.println("Nulling RO index");
0665: resetRolloverIndex();
0666: } else {
0667: // special case - check the month bounds of the matching day
0668: Rectangle monthBounds = getMonthBounds(matchingDay);
0669: if ((monthBounds == null)
0670: || !monthBounds.contains(e.getPoint())) {
0671: // either trailing or leading day
0672: this .fadeOutDay();
0673: this .fadeOutMonth();
0674: resetRolloverIndex();
0675: } else {
0676: Calendar cal = monthView.getCalendar();
0677: cal.setTime(matchingDay);
0678: int roIndexDay = cal.get(Calendar.DAY_OF_MONTH);
0679: int roIndexMonth = cal.get(Calendar.MONTH);
0680: int roIndexYear = cal.get(Calendar.YEAR);
0681: // check if this is the same index
0682: if ((rolloverDayId >= 0)
0683: && (rolloverDayId == roIndexDay)
0684: && (rolloverMonthId >= 0)
0685: && (rolloverMonthId == roIndexMonth)
0686: && (rolloverYearId >= 0)
0687: && (rolloverYearId == roIndexYear))
0688: return;
0689:
0690: this .fadeOutDay();
0691: boolean isDifferentMonth = (rolloverMonthId != roIndexMonth);
0692: if (isDifferentMonth) {
0693: this .fadeOutMonth();
0694: }
0695: rolloverDayId = roIndexDay;
0696: rolloverMonthId = roIndexMonth;
0697: rolloverYearId = roIndexYear;
0698: FadeTracker.getInstance().trackFadeIn(
0699: FadeKind.ROLLOVER,
0700: monthView,
0701: rolloverDayId + ":" + rolloverMonthId + ":"
0702: + rolloverYearId,
0703: false,
0704: new DayRepaintCallback(monthView,
0705: rolloverDayId, rolloverMonthId,
0706: rolloverYearId));
0707:
0708: if (isDifferentMonth) {
0709: FadeTracker.getInstance()
0710: .trackFadeIn(
0711: FadeKind.ROLLOVER,
0712: monthView,
0713: rolloverMonthId + ":"
0714: + rolloverYearId,
0715: false,
0716: new MonthRepaintCallback(
0717: monthView,
0718: rolloverMonthId,
0719: rolloverYearId));
0720: // System.out.println("Fading in " + rolloverMonthId +
0721: // ":"
0722: // + rolloverYearId);
0723: }
0724: // System.out.println("Setting RO index to " + roIndex);
0725: }
0726: }
0727: }
0728:
0729: /**
0730: * Initiates the fade out effect on the specific day.
0731: */
0732: private void fadeOutDay() {
0733: if ((rolloverDayId < 0) || (rolloverMonthId < 0)
0734: || (rolloverYearId < 0))
0735: return;
0736:
0737: FadeTracker.getInstance().trackFadeOut(
0738: FadeKind.ROLLOVER,
0739: monthView,
0740: rolloverDayId + ":" + rolloverMonthId + ":"
0741: + rolloverYearId,
0742: false,
0743: new DayRepaintCallback(monthView, rolloverDayId,
0744: rolloverMonthId, rolloverYearId));
0745: }
0746:
0747: /**
0748: * Initiates the fade out effect on the specific month.
0749: */
0750: private void fadeOutMonth() {
0751: if ((rolloverMonthId < 0) || (rolloverYearId < 0))
0752: return;
0753:
0754: FadeTracker.getInstance().trackFadeOut(
0755: FadeKind.ROLLOVER,
0756: monthView,
0757: rolloverMonthId + ":" + rolloverYearId,
0758: false,
0759: new MonthRepaintCallback(monthView,
0760: rolloverMonthId, rolloverYearId));
0761: // System.out.println("Fading out " + rolloverMonthId + ":"
0762: // + rolloverYearId);
0763: }
0764: }
0765:
0766: /**
0767: * Repaints a single month during the fade animation cycle.
0768: *
0769: * @author Kirill Grouchnikov
0770: */
0771: protected class MonthRepaintCallback extends FadeTrackerAdapter {
0772: /**
0773: * Associated control.
0774: */
0775: protected JXMonthView monthView;
0776:
0777: /**
0778: * Associated (animated) month index.
0779: */
0780: protected int monthIndex;
0781:
0782: protected int yearIndex;
0783:
0784: /**
0785: * Creates a new animation repaint callback.
0786: *
0787: * @param monthView
0788: * Associated control.
0789: * @param monthIndex
0790: * Associated (animated) month index.
0791: */
0792: public MonthRepaintCallback(JXMonthView monthView,
0793: int monthIndex, int yearIndex) {
0794: this .monthView = monthView;
0795: this .monthIndex = monthIndex;
0796: this .yearIndex = yearIndex;
0797: }
0798:
0799: /*
0800: * (non-Javadoc)
0801: *
0802: * @see org.jvnet.lafwidget.utils.FadeTracker$FadeTrackerCallback#fadeEnded(org.jvnet.lafwidget.utils.FadeTracker.FadeKind)
0803: */
0804: @Override
0805: public void fadeEnded(FadeKind fadeKind) {
0806: if (monthView == SubstanceMonthViewUI.this .monthView) {
0807: String key = this .monthIndex + ":" + this .yearIndex;
0808: ComponentState currState = SubstanceMonthViewUI.this
0809: .getMonthState(this .monthIndex, this .yearIndex);
0810: if (currState == ComponentState.DEFAULT) {
0811: prevMonthStateMap.remove(key);
0812: nextMonthStateMap.remove(key);
0813: } else {
0814: prevMonthStateMap.put(key, currState);
0815: nextMonthStateMap.put(key, currState);
0816: }
0817: }
0818: this .repaintCell();
0819: }
0820:
0821: /*
0822: * (non-Javadoc)
0823: *
0824: * @see org.jvnet.lafwidget.animation.FadeTrackerAdapter#fadeReversed(org.jvnet.lafwidget.animation.FadeKind,
0825: * boolean, float)
0826: */
0827: @Override
0828: public void fadeReversed(FadeKind fadeKind, boolean isFadingIn,
0829: float fadeCycle10) {
0830: if (monthView == SubstanceMonthViewUI.this .monthView) {
0831: String key = this .monthIndex + ":" + this .yearIndex;
0832: ComponentState nextState = nextMonthStateMap.get(key);
0833: if (nextState == null) {
0834: prevMonthStateMap.remove(key);
0835: } else {
0836: prevMonthStateMap.put(key, nextState);
0837: }
0838: // System.out.println(tabIndex + "->"
0839: // + prevStateMap.get(tabIndex).name());
0840: }
0841: this .repaintCell();
0842: }
0843:
0844: /*
0845: * (non-Javadoc)
0846: *
0847: * @see org.jvnet.lafwidget.utils.FadeTracker$FadeTrackerCallback#fadePerformed(org.jvnet.lafwidget.utils.FadeTracker.FadeKind,
0848: * float)
0849: */
0850: @Override
0851: public void fadePerformed(FadeKind fadeKind, float fade10) {
0852: // System.out.println("Fade on " + this.dayIndex + ":"
0853: // + this.monthIndex + ":" + this.yearIndex + " at " + fade10);
0854: if (monthView == SubstanceMonthViewUI.this .monthView) {
0855: String key = this .monthIndex + ":" + this .yearIndex;
0856:
0857: nextMonthStateMap.put(key, getMonthState(
0858: this .monthIndex, this .yearIndex));
0859: }
0860: this .repaintCell();
0861: }
0862:
0863: /**
0864: * Repaints the associated cell.
0865: */
0866: private void repaintCell() {
0867: SwingUtilities.invokeLater(new Runnable() {
0868: public void run() {
0869: if (monthView != SubstanceMonthViewUI.this .monthView) {
0870: // may happen if the LAF was switched in the meantime
0871: return;
0872: }
0873: Calendar cal = monthView.getCalendar();
0874: cal.set(Calendar.MONTH, monthIndex);
0875: cal.set(Calendar.YEAR, yearIndex);
0876: Rectangle monthBounds = getMonthBounds(cal
0877: .getTime());
0878: // Rectangle monthTitleBounds = monthTitleBoundsMap
0879: // .get(monthIndex + ":" + yearIndex);
0880: if (monthBounds != null) {
0881: monthView.repaint(monthBounds);
0882: }
0883: }
0884: });
0885: }
0886: }
0887:
0888: /**
0889: * Repaints a single day during the fade animation cycle.
0890: *
0891: * @author Kirill Grouchnikov
0892: */
0893: protected class DayRepaintCallback extends FadeTrackerAdapter {
0894: /**
0895: * Associated control.
0896: */
0897: protected JXMonthView monthView;
0898:
0899: /**
0900: * Associated (animated) day index.
0901: */
0902: protected int dayIndex;
0903:
0904: protected int monthIndex;
0905:
0906: protected int yearIndex;
0907:
0908: /**
0909: * Creates a new animation repaint callback.
0910: *
0911: * @param monthView
0912: * Associated control.
0913: * @param dayIndex
0914: * Associated (animated) day index.
0915: */
0916: public DayRepaintCallback(JXMonthView monthView, int dayIndex,
0917: int monthIndex, int yearIndex) {
0918: this .monthView = monthView;
0919: this .dayIndex = dayIndex;
0920: this .monthIndex = monthIndex;
0921: this .yearIndex = yearIndex;
0922: }
0923:
0924: /*
0925: * (non-Javadoc)
0926: *
0927: * @see org.jvnet.lafwidget.utils.FadeTracker$FadeTrackerCallback#fadeEnded(org.jvnet.lafwidget.utils.FadeTracker.FadeKind)
0928: */
0929: @Override
0930: public void fadeEnded(FadeKind fadeKind) {
0931: String key = this .dayIndex + ":" + this .monthIndex + ":"
0932: + this .yearIndex;
0933: if (monthView == SubstanceMonthViewUI.this .monthView) {
0934: ComponentState currState = SubstanceMonthViewUI.this
0935: .getDayState(this .dayIndex, this .monthIndex,
0936: this .yearIndex);
0937: if (currState == ComponentState.DEFAULT) {
0938: prevDayStateMap.remove(key);
0939: nextDayStateMap.remove(key);
0940: } else {
0941: prevDayStateMap.put(key, currState);
0942: nextDayStateMap.put(key, currState);
0943: }
0944: // System.out.println(tabIndex + "->"
0945: // + prevStateMap.get(tabIndex).name());
0946: }
0947: this .repaintCell();
0948: }
0949:
0950: /*
0951: * (non-Javadoc)
0952: *
0953: * @see org.jvnet.lafwidget.animation.FadeTrackerAdapter#fadeReversed(org.jvnet.lafwidget.animation.FadeKind,
0954: * boolean, float)
0955: */
0956: @Override
0957: public void fadeReversed(FadeKind fadeKind, boolean isFadingIn,
0958: float fadeCycle10) {
0959: if (monthView == SubstanceMonthViewUI.this .monthView) {
0960: String key = this .dayIndex + ":" + this .monthIndex
0961: + ":" + this .yearIndex;
0962: ComponentState nextState = nextDayStateMap.get(key);
0963: if (nextState == null) {
0964: prevDayStateMap.remove(key);
0965: } else {
0966: prevDayStateMap.put(key, nextState);
0967: }
0968: // System.out.println(tabIndex + "->"
0969: // + prevStateMap.get(tabIndex).name());
0970: }
0971: this .repaintCell();
0972: }
0973:
0974: /*
0975: * (non-Javadoc)
0976: *
0977: * @see org.jvnet.lafwidget.utils.FadeTracker$FadeTrackerCallback#fadePerformed(org.jvnet.lafwidget.utils.FadeTracker.FadeKind,
0978: * float)
0979: */
0980: @Override
0981: public void fadePerformed(FadeKind fadeKind, float fade10) {
0982: // System.out.println("Fade on " + this.dayIndex + ":"
0983: // + this.monthIndex + ":" + this.yearIndex + " at " + fade10);
0984: if (monthView == SubstanceMonthViewUI.this .monthView) {
0985: String key = this .dayIndex + ":" + this .monthIndex
0986: + ":" + this .yearIndex;
0987: nextDayStateMap.put(key, getDayState(this .dayIndex,
0988: this .monthIndex, this .yearIndex));
0989: }
0990: this .repaintCell();
0991: }
0992:
0993: /**
0994: * Repaints the associated cell.
0995: */
0996: private void repaintCell() {
0997: SwingUtilities.invokeLater(new Runnable() {
0998: public void run() {
0999: if (monthView != SubstanceMonthViewUI.this .monthView) {
1000: // may happen if the LAF was switched in the meantime
1001: return;
1002: }
1003: Calendar cal = monthView.getCalendar();
1004: cal.set(Calendar.DAY_OF_MONTH, dayIndex);
1005: cal.set(Calendar.MONTH, monthIndex);
1006: cal.set(Calendar.YEAR, yearIndex);
1007:
1008: Rectangle dayBounds = getDayBounds(cal.getTime());
1009: if (dayBounds != null) {
1010: DayRepaintCallback.this .monthView
1011: .repaint(dayBounds);
1012: }
1013: }
1014: });
1015: }
1016: }
1017:
1018: /**
1019: * Returns the current state for the specified day.
1020: *
1021: * @param dayIndex
1022: * Day index.
1023: * @return The current state for the specified day.
1024: */
1025: public ComponentState getDayState(int dayIndex, int monthIndex,
1026: int yearIndex) {
1027: ButtonModel synthModel = new DefaultButtonModel();
1028: synthModel.setEnabled(this .monthView.isEnabled());
1029: // Integer currRoIndex = (Integer) list
1030: // .getClientProperty(ROLLED_OVER_INDEX);
1031: synthModel.setRollover((this .rolloverDayId >= 0)
1032: && (this .rolloverDayId == dayIndex)
1033: && (this .rolloverMonthId >= 0)
1034: && (this .rolloverMonthId == monthIndex)
1035: && (this .rolloverYearId >= 0)
1036: && (this .rolloverYearId == yearIndex));
1037: Calendar cal = this .monthView.getCalendar();
1038: cal.set(Calendar.DAY_OF_MONTH, dayIndex);
1039: cal.set(Calendar.MONTH, monthIndex);
1040: cal.set(Calendar.YEAR, yearIndex);
1041: synthModel
1042: .setSelected(this .monthView.isSelected(cal.getTime()));
1043: return ComponentState.getState(synthModel, null);
1044: }
1045:
1046: /**
1047: * Returns the current state for the specified month.
1048: *
1049: * @param dayIndex
1050: * Day index.
1051: * @return The current state for the specified month.
1052: */
1053: public ComponentState getMonthState(int monthIndex, int yearIndex) {
1054: ButtonModel synthModel = new DefaultButtonModel();
1055: synthModel.setEnabled(this .monthView.isEnabled());
1056: synthModel.setRollover((this .rolloverMonthId >= 0)
1057: && (this .rolloverMonthId == monthIndex)
1058: && (this .rolloverYearId >= 0)
1059: && (this .rolloverYearId == yearIndex));
1060: return ComponentState.getState(synthModel, null);
1061: }
1062:
1063: /**
1064: * Returns the previous state for the specified day.
1065: *
1066: * @param dayIndex
1067: * Day index.
1068: * @return The previous state for the specified day.
1069: */
1070: public ComponentState getPrevDayState(int dayIndex, int monthIndex,
1071: int yearIndex) {
1072: String key = dayIndex + ":" + monthIndex + ":" + yearIndex;
1073: if (this .prevDayStateMap.containsKey(key))
1074: return this .prevDayStateMap.get(key);
1075: return ComponentState.DEFAULT;
1076: }
1077:
1078: /**
1079: * Returns the previous state for the specified day.
1080: *
1081: * @param dayIndex
1082: * Day index.
1083: * @return The previous state for the specified day.
1084: */
1085: public ComponentState getPrevMonthState(int monthIndex,
1086: int yearIndex) {
1087: String key = monthIndex + ":" + yearIndex;
1088: if (this .prevMonthStateMap.containsKey(key))
1089: return this .prevMonthStateMap.get(key);
1090: return ComponentState.DEFAULT;
1091: }
1092:
1093: /**
1094: * Resets the rollover index.
1095: */
1096: protected void resetRolloverIndex() {
1097: this .rolloverDayId = -1;
1098: this .rolloverMonthId = -1;
1099: this .rolloverYearId = -1;
1100: }
1101: }
|