~ubuntu-branches/debian/stretch/insubstantial/stretch

« back to all changes in this revision

Viewing changes to substance-swingx/src/main/java/org/pushingpixels/substance/swingx/SubstanceMonthViewUI.java

  • Committer: Package Import Robot
  • Author(s): Felix Natter
  • Date: 2016-01-18 20:58:45 UTC
  • Revision ID: package-import@ubuntu.com-20160118205845-crbmrkda61qsi5qa
Tags: upstream-7.3+dfsg2
ImportĀ upstreamĀ versionĀ 7.3+dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2005-2010 Kirill Grouchnikov, based on work by
 
3
 * Sun Microsystems, Inc. All rights reserved.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2.1 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
package org.pushingpixels.substance.swingx;
 
20
 
 
21
import java.awt.Color;
 
22
import java.awt.Graphics;
 
23
import java.awt.Graphics2D;
 
24
import java.awt.Rectangle;
 
25
import java.awt.event.MouseEvent;
 
26
import java.awt.event.MouseListener;
 
27
import java.awt.event.MouseMotionListener;
 
28
import java.util.Calendar;
 
29
import java.util.Date;
 
30
import java.util.HashSet;
 
31
import java.util.Iterator;
 
32
import java.util.Map;
 
33
import java.util.Set;
 
34
 
 
35
import javax.swing.BorderFactory;
 
36
import javax.swing.ButtonModel;
 
37
import javax.swing.DefaultButtonModel;
 
38
import javax.swing.JComponent;
 
39
import javax.swing.SwingConstants;
 
40
import javax.swing.SwingUtilities;
 
41
import javax.swing.border.Border;
 
42
import javax.swing.plaf.ComponentUI;
 
43
import javax.swing.plaf.UIResource;
 
44
import javax.swing.plaf.basic.BasicLookAndFeel;
 
45
 
 
46
import org.jdesktop.swingx.JXMonthView;
 
47
import org.jdesktop.swingx.border.IconBorder;
 
48
import org.jdesktop.swingx.calendar.DateSelectionModel;
 
49
import org.jdesktop.swingx.event.DateSelectionEvent;
 
50
import org.jdesktop.swingx.event.DateSelectionListener;
 
51
import org.jdesktop.swingx.plaf.basic.BasicMonthViewUI;
 
52
import org.jdesktop.swingx.plaf.basic.CalendarState;
 
53
import org.pushingpixels.lafwidget.LafWidgetUtilities;
 
54
import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager;
 
55
import org.pushingpixels.lafwidget.animation.AnimationFacet;
 
56
import org.pushingpixels.substance.api.ColorSchemeAssociationKind;
 
57
import org.pushingpixels.substance.api.ComponentState;
 
58
import org.pushingpixels.substance.api.ComponentStateFacet;
 
59
import org.pushingpixels.substance.api.SubstanceColorScheme;
 
60
import org.pushingpixels.substance.internal.animation.StateTransitionMultiTracker;
 
61
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
 
62
import org.pushingpixels.substance.internal.animation.TransitionAwareUI;
 
63
import org.pushingpixels.substance.internal.animation.StateTransitionTracker.RepaintCallback;
 
64
import org.pushingpixels.substance.internal.painter.BackgroundPaintingUtils;
 
65
import org.pushingpixels.substance.internal.painter.HighlightPainterUtils;
 
66
import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities;
 
67
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
 
68
import org.pushingpixels.substance.internal.utils.SubstanceImageCreator;
 
69
import org.pushingpixels.substance.internal.utils.SubstanceTextUtilities;
 
70
import org.pushingpixels.trident.Timeline.TimelineState;
 
71
import org.pushingpixels.trident.callback.TimelineCallback;
 
72
import org.pushingpixels.trident.callback.UIThreadTimelineCallbackAdapter;
 
73
 
 
74
/**
 
75
 * Substance-consistent UI delegate for {@link JXMonthView}.
 
76
 * 
 
77
 * @author Kirill Grouchnikov
 
78
 */
 
79
public class SubstanceMonthViewUI extends BasicMonthViewUI implements
 
80
                TransitionAwareUI {
 
81
        /**
 
82
         * Listener for transition animations on rollovers.
 
83
         */
 
84
        protected DayRolloverFadeListener substanceFadeRolloverListener;
 
85
 
 
86
        protected DateId rolloverDateId;
 
87
 
 
88
        /**
 
89
         * Holds the list of currently selected days. Every entry is day:month:year
 
90
         */
 
91
        protected Set<DateId> selectedDates;
 
92
 
 
93
        /**
 
94
         * Listener for transition animations on day selections.
 
95
         */
 
96
        protected DateSelectionListener substanceFadeSelectionListener;
 
97
 
 
98
        private StateTransitionMultiTracker<DateId> dayStateTransitionMultiTracker;
 
99
 
 
100
        private StateTransitionMultiTracker<MonthId> monthStateTransitionMultiTracker;
 
101
 
 
102
        static class DateId implements Comparable<DateId> {
 
103
                protected int day;
 
104
 
 
105
                protected int month;
 
106
 
 
107
                protected int year;
 
108
 
 
109
                public DateId(int day, int month, int year) {
 
110
                        this.day = day;
 
111
                        this.month = month;
 
112
                        this.year = year;
 
113
                }
 
114
 
 
115
                @Override
 
116
                public int compareTo(DateId o) {
 
117
                        if ((this.day == o.day) && (this.month == o.month)
 
118
                                        && (this.year == o.year))
 
119
                                return 0;
 
120
                        return 1;
 
121
                }
 
122
 
 
123
                @Override
 
124
                public boolean equals(Object obj) {
 
125
                        if (obj instanceof DateId) {
 
126
                                return this.compareTo((DateId) obj) == 0;
 
127
                        }
 
128
                        return false;
 
129
                }
 
130
 
 
131
                @Override
 
132
                public int hashCode() {
 
133
                        return (this.day ^ (this.day >>> 32))
 
134
                                        & (this.month ^ (this.month >>> 32))
 
135
                                        & (this.year ^ (this.year >>> 32));
 
136
                }
 
137
 
 
138
                @Override
 
139
                public String toString() {
 
140
                        return "Day " + this.day + ", Month " + this.month + ", Year "
 
141
                                        + this.year;
 
142
                }
 
143
        }
 
144
 
 
145
        static class MonthId implements Comparable<MonthId> {
 
146
                protected int month;
 
147
 
 
148
                protected int year;
 
149
 
 
150
                public MonthId(int month, int year) {
 
151
                        this.month = month;
 
152
                        this.year = year;
 
153
                }
 
154
 
 
155
                @Override
 
156
                public int compareTo(MonthId o) {
 
157
                        if ((this.month == o.month) && (this.year == o.year))
 
158
                                return 0;
 
159
                        return 1;
 
160
                }
 
161
 
 
162
                @Override
 
163
                public boolean equals(Object obj) {
 
164
                        if (obj instanceof MonthId) {
 
165
                                return this.compareTo((MonthId) obj) == 0;
 
166
                        }
 
167
                        return false;
 
168
                }
 
169
 
 
170
                @Override
 
171
                public int hashCode() {
 
172
                        return (this.month ^ (this.month >>> 32))
 
173
                                        & (this.year ^ (this.year >>> 32));
 
174
                }
 
175
 
 
176
                @Override
 
177
                public String toString() {
 
178
                        return "Month " + this.month + ", Year " + this.year;
 
179
                }
 
180
        }
 
181
 
 
182
        public static ComponentUI createUI(JComponent comp) {
 
183
                SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
 
184
                return new SubstanceMonthViewUI();
 
185
        }
 
186
 
 
187
        /**
 
188
         * Creates a new UI delegate.
 
189
         */
 
190
        public SubstanceMonthViewUI() {
 
191
                super();
 
192
 
 
193
                this.dayStateTransitionMultiTracker = new StateTransitionMultiTracker<DateId>();
 
194
                this.monthStateTransitionMultiTracker = new StateTransitionMultiTracker<MonthId>();
 
195
                this.selectedDates = new HashSet<DateId>();
 
196
        }
 
197
 
 
198
        /*
 
199
         * (non-Javadoc)
 
200
         * 
 
201
         * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installDefaults()
 
202
         */
 
203
        @Override
 
204
        protected void installDefaults() {
 
205
                super.installDefaults();
 
206
                BasicLookAndFeel.installColors(this.monthView,
 
207
                                "JXMonthView.background", "JXMonthView.foreground");
 
208
 
 
209
                Calendar cal = this.monthView.getCalendar();
 
210
                if (cal != null) {
 
211
                        for (Date selected : this.getSelection()) {
 
212
                                cal.setTime(selected);
 
213
                                int day = cal.get(Calendar.DAY_OF_MONTH);
 
214
                                int month = cal.get(Calendar.MONTH);
 
215
                                int year = cal.get(Calendar.YEAR);
 
216
                                this.selectedDates.add(new DateId(day, month, year));
 
217
                        }
 
218
                }
 
219
        }
 
220
 
 
221
        /*
 
222
         * (non-Javadoc)
 
223
         * 
 
224
         * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installDelegate()
 
225
         */
 
226
        @Override
 
227
        protected void installDelegate() {
 
228
                super.installDelegate();
 
229
                this.monthDownImage = SubstanceImageCreator.getArrowIcon(this.monthView
 
230
                                .getFont().getSize(), SwingConstants.WEST,
 
231
                                SubstanceColorSchemeUtilities
 
232
                                                .getColorScheme(this.monthView,
 
233
                                                                ColorSchemeAssociationKind.MARK,
 
234
                                                                ComponentState.ENABLED));
 
235
                this.monthUpImage = SubstanceImageCreator.getArrowIcon(this.monthView
 
236
                                .getFont().getSize(), SwingConstants.EAST,
 
237
                                SubstanceColorSchemeUtilities
 
238
                                                .getColorScheme(this.monthView,
 
239
                                                                ColorSchemeAssociationKind.MARK,
 
240
                                                                ComponentState.ENABLED));
 
241
        }
 
242
 
 
243
        /*
 
244
         * (non-Javadoc)
 
245
         * 
 
246
         * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installListeners()
 
247
         */
 
248
        @Override
 
249
        protected void installListeners() {
 
250
                super.installListeners();
 
251
 
 
252
                this.substanceFadeRolloverListener = new DayRolloverFadeListener();
 
253
                this.monthView.addMouseMotionListener(substanceFadeRolloverListener);
 
254
                this.monthView.addMouseListener(substanceFadeRolloverListener);
 
255
 
 
256
                // Add listener for the selection animation
 
257
                substanceFadeSelectionListener = new DateSelectionListener() {
 
258
                        public void valueChanged(DateSelectionEvent ev) {
 
259
                                // System.out.println("Has "
 
260
                                // + monthView.getSelectionModel().getSelection().size());
 
261
 
 
262
                                // try {
 
263
                                boolean hasSelectionAnimations = !LafWidgetUtilities
 
264
                                                .hasNoAnimations(monthView, AnimationFacet.SELECTION);
 
265
 
 
266
                                Calendar cal = monthView.getCalendar();
 
267
 
 
268
                                DateSelectionModel selectionModel = monthView
 
269
                                                .getSelectionModel();
 
270
 
 
271
                                for (Iterator<DateId> selIt = selectedDates.iterator(); selIt
 
272
                                                .hasNext();) {
 
273
                                        DateId currSelected = selIt.next();
 
274
                                        // still selected?
 
275
                                        cal.set(Calendar.DAY_OF_MONTH, currSelected.day);
 
276
                                        cal.set(Calendar.MONTH, currSelected.month);
 
277
                                        cal.set(Calendar.YEAR, currSelected.year);
 
278
                                        if (selectionModel.isSelected(cal.getTime()))
 
279
                                                continue;
 
280
 
 
281
                                        if (hasSelectionAnimations) {
 
282
                                                StateTransitionTracker tracker = getDayTracker(
 
283
                                                                currSelected, getDayState(currSelected.day,
 
284
                                                                                currSelected.month, currSelected.year)
 
285
                                                                                .isFacetActive(
 
286
                                                                                                ComponentStateFacet.ROLLOVER),
 
287
                                                                true);
 
288
                                                tracker.getModel().setSelected(false);
 
289
                                        }
 
290
                                        selIt.remove();
 
291
                                }
 
292
 
 
293
                                for (Date newlySelected : selectionModel.getSelection()) {
 
294
                                        cal.setTime(newlySelected);
 
295
                                        DateId newlySelectedDate = new DateId(cal
 
296
                                                        .get(Calendar.DAY_OF_MONTH), cal
 
297
                                                        .get(Calendar.MONTH), cal.get(Calendar.YEAR));
 
298
                                        if (selectedDates.contains(newlySelectedDate))
 
299
                                                continue;
 
300
 
 
301
                                        if (hasSelectionAnimations) {
 
302
                                                StateTransitionTracker tracker = getDayTracker(
 
303
                                                                newlySelectedDate, getDayState(
 
304
                                                                                newlySelectedDate.day,
 
305
                                                                                newlySelectedDate.month,
 
306
                                                                                newlySelectedDate.year).isFacetActive(
 
307
                                                                                ComponentStateFacet.ROLLOVER), false);
 
308
                                                tracker.getModel().setSelected(true);
 
309
                                        }
 
310
                                        selectedDates.add(newlySelectedDate);
 
311
                                }
 
312
                        }
 
313
                };
 
314
                this.monthView.getSelectionModel().addDateSelectionListener(
 
315
                                this.substanceFadeSelectionListener);
 
316
        }
 
317
 
 
318
        /*
 
319
         * (non-Javadoc)
 
320
         * 
 
321
         * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#uninstallListeners()
 
322
         */
 
323
        @Override
 
324
        protected void uninstallListeners() {
 
325
                this.monthView.getSelectionModel().removeDateSelectionListener(
 
326
                                this.substanceFadeSelectionListener);
 
327
                this.substanceFadeSelectionListener = null;
 
328
 
 
329
                this.monthView.removeMouseListener(this.substanceFadeRolloverListener);
 
330
                this.monthView
 
331
                                .removeMouseMotionListener(this.substanceFadeRolloverListener);
 
332
                this.substanceFadeRolloverListener = null;
 
333
 
 
334
                super.uninstallListeners();
 
335
        }
 
336
 
 
337
        /*
 
338
         * (non-Javadoc)
 
339
         * 
 
340
         * @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#uninstallDefaults()
 
341
         */
 
342
        @Override
 
343
        protected void uninstallDefaults() {
 
344
                this.selectedDates.clear();
 
345
 
 
346
                super.uninstallDefaults();
 
347
        }
 
348
 
 
349
        /*
 
350
         * (non-Javadoc)
 
351
         * 
 
352
         * @see
 
353
         * org.jvnet.substance.utils.Trackable#isInside(java.awt.event.MouseEvent)
 
354
         */
 
355
        public boolean isInside(MouseEvent me) {
 
356
                // The entire component area is considered as trackable for rollover
 
357
                // effects.
 
358
                return true;
 
359
        }
 
360
 
 
361
        @Override
 
362
        public StateTransitionTracker getTransitionTracker() {
 
363
                return null;
 
364
        }
 
365
 
 
366
        /**
 
367
         * Listener for fade animations on month view rollovers.
 
368
         * 
 
369
         * @author Kirill Grouchnikov
 
370
         */
 
371
        private class DayRolloverFadeListener implements MouseListener,
 
372
                        MouseMotionListener {
 
373
                public void mouseClicked(MouseEvent e) {
 
374
                }
 
375
 
 
376
                public void mouseEntered(MouseEvent e) {
 
377
                }
 
378
 
 
379
                public void mousePressed(MouseEvent e) {
 
380
                }
 
381
 
 
382
                public void mouseReleased(MouseEvent e) {
 
383
                }
 
384
 
 
385
                public void mouseExited(MouseEvent e) {
 
386
                        this.fadeOutDay();
 
387
                        this.fadeOutMonth();
 
388
                        // System.out.println("Nulling RO index");
 
389
                        resetRolloverIndex();
 
390
                }
 
391
 
 
392
                public void mouseMoved(MouseEvent e) {
 
393
                        if (!monthView.isEnabled())
 
394
                                return;
 
395
                        this.handleMove(e);
 
396
                }
 
397
 
 
398
                public void mouseDragged(MouseEvent e) {
 
399
                        // if (SubstanceCoreUtilities.toBleedWatermark(list))
 
400
                        // return;
 
401
 
 
402
                        if (!monthView.isEnabled())
 
403
                                return;
 
404
                        this.handleMove(e);
 
405
                }
 
406
 
 
407
                /**
 
408
                 * Handles various mouse move events and initiates the fade animation if
 
409
                 * necessary.
 
410
                 * 
 
411
                 * @param e
 
412
                 *            Mouse event.
 
413
                 */
 
414
                private void handleMove(MouseEvent e) {
 
415
                        boolean fadeAllowed = AnimationConfigurationManager.getInstance()
 
416
                                        .isAnimationAllowed(AnimationFacet.ROLLOVER, monthView);
 
417
                        if (!fadeAllowed) {
 
418
                                this.fadeOutDay();
 
419
                                this.fadeOutMonth();
 
420
                                resetRolloverIndex();
 
421
                                return;
 
422
                        }
 
423
 
 
424
                        Date matchingDay = monthView.getDayAtLocation(e.getX(), e.getY());
 
425
                        if (matchingDay == null) {
 
426
                                this.fadeOutDay();
 
427
                                this.fadeOutMonth();
 
428
                                // System.out.println("Nulling RO index");
 
429
                                resetRolloverIndex();
 
430
                        } else {
 
431
                                // special case - check the month bounds of the matching day
 
432
                                Rectangle monthBounds = getMonthBounds(matchingDay);
 
433
                                if ((monthBounds == null)
 
434
                                                || !monthBounds.contains(e.getPoint())) {
 
435
                                        // either trailing or leading day
 
436
                                        this.fadeOutDay();
 
437
                                        this.fadeOutMonth();
 
438
                                        resetRolloverIndex();
 
439
                                } else {
 
440
                                        Calendar cal = monthView.getCalendar();
 
441
                                        cal.setTime(matchingDay);
 
442
                                        int roIndexDay = cal.get(Calendar.DAY_OF_MONTH);
 
443
                                        int roIndexMonth = cal.get(Calendar.MONTH);
 
444
                                        int roIndexYear = cal.get(Calendar.YEAR);
 
445
 
 
446
                                        DateId dateId = new DateId(roIndexDay, roIndexMonth,
 
447
                                                        roIndexYear);
 
448
                                        // check if this is the same index
 
449
                                        if (dateId.equals(rolloverDateId))
 
450
                                                return;
 
451
 
 
452
                                        this.fadeOutDay();
 
453
                                        boolean isDifferentMonth = (rolloverDateId == null)
 
454
                                                        || (rolloverDateId.month != roIndexMonth)
 
455
                                                        || (rolloverDateId.year != roIndexYear);
 
456
                                        if (isDifferentMonth) {
 
457
                                                this.fadeOutMonth();
 
458
                                        }
 
459
 
 
460
                                        rolloverDateId = dateId;
 
461
 
 
462
                                        StateTransitionTracker dayTracker = getDayTracker(dateId,
 
463
                                                        false, getDayState(roIndexDay, roIndexMonth,
 
464
                                                                        roIndexYear).isFacetActive(
 
465
                                                                        ComponentStateFacet.SELECTION));
 
466
                                        dayTracker.getModel().setRollover(true);
 
467
 
 
468
                                        if (isDifferentMonth) {
 
469
                                                StateTransitionTracker monthTracker = getMonthTracker(
 
470
                                                                new MonthId(roIndexMonth, roIndexYear), false,
 
471
                                                                getMonthState(roIndexMonth, roIndexYear)
 
472
                                                                                .isFacetActive(
 
473
                                                                                                ComponentStateFacet.SELECTION));
 
474
                                                monthTracker.getModel().setRollover(true);
 
475
                                                // System.out.println("Fading in " + rolloverMonthId +
 
476
                                                // ":"
 
477
                                                // + rolloverYearId);
 
478
                                        }
 
479
                                        // System.out.println("Setting RO index to " + roIndex);
 
480
                                }
 
481
                        }
 
482
                }
 
483
 
 
484
                /**
 
485
                 * Initiates the fade out effect on the specific day.
 
486
                 */
 
487
                private void fadeOutDay() {
 
488
                        if (rolloverDateId == null)
 
489
                                return;
 
490
 
 
491
                        StateTransitionTracker tracker = getDayTracker(rolloverDateId,
 
492
                                        true, getDayState(rolloverDateId.day, rolloverDateId.month,
 
493
                                                        rolloverDateId.year).isFacetActive(
 
494
                                                        ComponentStateFacet.SELECTION));
 
495
                        tracker.getModel().setRollover(false);
 
496
                }
 
497
 
 
498
                /**
 
499
                 * Initiates the fade out effect on the specific month.
 
500
                 */
 
501
                private void fadeOutMonth() {
 
502
                        if (rolloverDateId == null)
 
503
                                return;
 
504
 
 
505
                        StateTransitionTracker tracker = getMonthTracker(new MonthId(
 
506
                                        rolloverDateId.month, rolloverDateId.year), true,
 
507
                                        getMonthState(rolloverDateId.month, rolloverDateId.year)
 
508
                                                        .isFacetActive(ComponentStateFacet.SELECTION));
 
509
                        tracker.getModel().setRollover(false);
 
510
                }
 
511
        }
 
512
 
 
513
        /**
 
514
         * Repaints a single month during the fade animation cycle.
 
515
         * 
 
516
         * @author Kirill Grouchnikov
 
517
         */
 
518
        protected class MonthRepaintCallback extends
 
519
                        UIThreadTimelineCallbackAdapter {
 
520
                /**
 
521
                 * Associated control.
 
522
                 */
 
523
                protected JXMonthView monthView;
 
524
 
 
525
                /**
 
526
                 * Associated (animated) month index.
 
527
                 */
 
528
                protected int monthIndex;
 
529
 
 
530
                protected int yearIndex;
 
531
 
 
532
                /**
 
533
                 * Creates a new animation repaint callback.
 
534
                 * 
 
535
                 * @param monthView
 
536
                 *            Associated control.
 
537
                 * @param monthIndex
 
538
                 *            Associated (animated) month index.
 
539
                 */
 
540
                public MonthRepaintCallback(JXMonthView monthView, int monthIndex,
 
541
                                int yearIndex) {
 
542
                        this.monthView = monthView;
 
543
                        this.monthIndex = monthIndex;
 
544
                        this.yearIndex = yearIndex;
 
545
                }
 
546
 
 
547
                @Override
 
548
                public void onTimelinePulse(float durationFraction,
 
549
                                float timelinePosition) {
 
550
                        this.repaintCell();
 
551
                }
 
552
 
 
553
                @Override
 
554
                public void onTimelineStateChanged(TimelineState oldState,
 
555
                                TimelineState newState, float durationFraction,
 
556
                                float timelinePosition) {
 
557
                        this.repaintCell();
 
558
                }
 
559
 
 
560
                /**
 
561
                 * Repaints the associated cell.
 
562
                 */
 
563
                private void repaintCell() {
 
564
                        SwingUtilities.invokeLater(new Runnable() {
 
565
                                public void run() {
 
566
                                        if (monthView != SubstanceMonthViewUI.this.monthView) {
 
567
                                                // may happen if the LAF was switched in the meantime
 
568
                                                return;
 
569
                                        }
 
570
                                        Calendar cal = monthView.getCalendar();
 
571
                                        cal.set(Calendar.MONTH, monthIndex);
 
572
                                        cal.set(Calendar.YEAR, yearIndex);
 
573
                                        Rectangle monthBounds = getMonthBounds(cal.getTime());
 
574
                                        // Rectangle monthTitleBounds = monthTitleBoundsMap
 
575
                                        // .get(monthIndex + ":" + yearIndex);
 
576
                                        if (monthBounds != null) {
 
577
                                                monthView.repaint(monthBounds);
 
578
                                        }
 
579
                                }
 
580
                        });
 
581
                }
 
582
        }
 
583
 
 
584
        /**
 
585
         * Repaints a single day during the fade animation cycle.
 
586
         * 
 
587
         * @author Kirill Grouchnikov
 
588
         */
 
589
        protected class DayRepaintCallback extends UIThreadTimelineCallbackAdapter {
 
590
                /**
 
591
                 * Associated control.
 
592
                 */
 
593
                protected JXMonthView monthView;
 
594
 
 
595
                /**
 
596
                 * Associated (animated) day index.
 
597
                 */
 
598
                protected int dayIndex;
 
599
 
 
600
                protected int monthIndex;
 
601
 
 
602
                protected int yearIndex;
 
603
 
 
604
                /**
 
605
                 * Creates a new animation repaint callback.
 
606
                 * 
 
607
                 * @param monthView
 
608
                 *            Associated control.
 
609
                 * @param dayIndex
 
610
                 *            Associated (animated) day index.
 
611
                 */
 
612
                public DayRepaintCallback(JXMonthView monthView, int dayIndex,
 
613
                                int monthIndex, int yearIndex) {
 
614
                        this.monthView = monthView;
 
615
                        this.dayIndex = dayIndex;
 
616
                        this.monthIndex = monthIndex;
 
617
                        this.yearIndex = yearIndex;
 
618
                }
 
619
 
 
620
                @Override
 
621
                public void onTimelinePulse(float durationFraction,
 
622
                                float timelinePosition) {
 
623
                        this.repaintCell();
 
624
                }
 
625
 
 
626
                @Override
 
627
                public void onTimelineStateChanged(TimelineState oldState,
 
628
                                TimelineState newState, float durationFraction,
 
629
                                float timelinePosition) {
 
630
                        this.repaintCell();
 
631
                }
 
632
 
 
633
                /**
 
634
                 * Repaints the associated cell.
 
635
                 */
 
636
                private void repaintCell() {
 
637
                        SwingUtilities.invokeLater(new Runnable() {
 
638
                                public void run() {
 
639
                                        if (monthView != SubstanceMonthViewUI.this.monthView) {
 
640
                                                // may happen if the LAF was switched in the meantime
 
641
                                                return;
 
642
                                        }
 
643
                                        Calendar cal = monthView.getCalendar();
 
644
                                        cal.set(Calendar.DAY_OF_MONTH, dayIndex);
 
645
                                        cal.set(Calendar.MONTH, monthIndex);
 
646
                                        cal.set(Calendar.YEAR, yearIndex);
 
647
 
 
648
                                        Rectangle dayBounds = getDayBounds(cal.getTime());
 
649
 
 
650
                                        if (dayBounds != null) {
 
651
                                                DayRepaintCallback.this.monthView.repaint(dayBounds);
 
652
                                        }
 
653
                                }
 
654
                        });
 
655
                }
 
656
        }
 
657
 
 
658
        private ComponentState getDayState(int dayIndex, int monthIndex,
 
659
                        int yearIndex) {
 
660
                DateId dateId = new DateId(dayIndex, monthIndex, yearIndex);
 
661
                boolean isEnabled = this.monthView.isEnabled();
 
662
                StateTransitionTracker tracker = this.dayStateTransitionMultiTracker
 
663
                                .getTracker(dateId);
 
664
                if (tracker == null) {
 
665
                        boolean isRollover = dateId.equals(this.rolloverDateId);
 
666
                        boolean isSelected = this.selectedDates.contains(dateId);
 
667
                        return ComponentState.getState(isEnabled, isRollover, isSelected);
 
668
                } else {
 
669
                        ComponentState fromTracker = tracker.getModelStateInfo()
 
670
                                        .getCurrModelState();
 
671
                        return ComponentState.getState(isEnabled, fromTracker
 
672
                                        .isFacetActive(ComponentStateFacet.ROLLOVER), fromTracker
 
673
                                        .isFacetActive(ComponentStateFacet.SELECTION));
 
674
                }
 
675
        }
 
676
 
 
677
        private ComponentState getMonthState(int monthIndex, int yearIndex) {
 
678
                MonthId monthId = new MonthId(monthIndex, yearIndex);
 
679
                boolean isEnabled = this.monthView.isEnabled();
 
680
                StateTransitionTracker tracker = this.monthStateTransitionMultiTracker
 
681
                                .getTracker(monthId);
 
682
                if (tracker == null) {
 
683
                        boolean isRollover = (this.rolloverDateId != null)
 
684
                                        && (this.rolloverDateId.month == monthIndex)
 
685
                                        && (this.rolloverDateId.year == yearIndex);
 
686
                        return ComponentState.getState(isEnabled, isRollover, false);
 
687
                } else {
 
688
                        ComponentState fromTracker = tracker.getModelStateInfo()
 
689
                                        .getCurrModelState();
 
690
                        return ComponentState.getState(isEnabled, fromTracker
 
691
                                        .isFacetActive(ComponentStateFacet.ROLLOVER), fromTracker
 
692
                                        .isFacetActive(ComponentStateFacet.SELECTION));
 
693
                }
 
694
        }
 
695
 
 
696
        /**
 
697
         * Resets the rollover index.
 
698
         */
 
699
        public void resetRolloverIndex() {
 
700
                this.rolloverDateId = null;
 
701
        }
 
702
 
 
703
        /*
 
704
         * (non-Javadoc)
 
705
         * 
 
706
         * @see
 
707
         * org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#createRenderingHandler()
 
708
         */
 
709
        @Override
 
710
        protected RenderingHandler createRenderingHandler() {
 
711
                // return null;
 
712
                return new SubstanceRenderingHandler();
 
713
        }
 
714
 
 
715
        @Override
 
716
        protected void paintMonthHeader(Graphics g, Calendar calendar) {
 
717
                Rectangle page = getMonthHeaderBounds(calendar.getTime(), false);
 
718
                int month = calendar.get(Calendar.MONTH);
 
719
                int year = calendar.get(Calendar.YEAR);
 
720
 
 
721
                Graphics2D g2d = (Graphics2D) g.create();
 
722
 
 
723
                ComponentState componentState = monthView.isEnabled() ? ComponentState.ENABLED
 
724
                                : ComponentState.DISABLED_UNSELECTED;
 
725
                float fillAlpha = SubstanceColorSchemeUtilities.getAlpha(monthView,
 
726
                                componentState);
 
727
                g2d.setComposite(LafWidgetUtilities.getAlphaComposite(monthView,
 
728
                                fillAlpha, g));
 
729
                SubstanceColorScheme bgFillScheme = SubstanceColorSchemeUtilities
 
730
                                .getColorScheme(monthView,
 
731
                                                ColorSchemeAssociationKind.HIGHLIGHT, componentState);
 
732
                SubstanceColorScheme bgBorderScheme = SubstanceColorSchemeUtilities
 
733
                                .getColorScheme(monthView,
 
734
                                                ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
 
735
                                                componentState);
 
736
                HighlightPainterUtils.paintHighlight(g2d, null, monthView, page, 0.5f,
 
737
                                null, bgFillScheme, bgBorderScheme);
 
738
                g2d.setComposite(LafWidgetUtilities.getAlphaComposite(monthView, g));
 
739
 
 
740
                StateTransitionTracker monthTracker = this.monthStateTransitionMultiTracker
 
741
                                .getTracker(new MonthId(month, year));
 
742
                StateTransitionTracker.ModelStateInfo modelStateInfo = (monthTracker == null) ? null
 
743
                                : monthTracker.getModelStateInfo();
 
744
                Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = ((modelStateInfo == null) ? null
 
745
                                : modelStateInfo.getStateContributionMap());
 
746
                ComponentState currState = ((modelStateInfo == null) ? getMonthState(
 
747
                                month, year) : modelStateInfo.getCurrModelState());
 
748
 
 
749
                if (activeStates == null) {
 
750
                        SubstanceColorScheme currFillScheme = SubstanceColorSchemeUtilities
 
751
                                        .getColorScheme(monthView,
 
752
                                                        ColorSchemeAssociationKind.HIGHLIGHT, currState);
 
753
                        SubstanceColorScheme currBorderScheme = SubstanceColorSchemeUtilities
 
754
                                        .getColorScheme(monthView,
 
755
                                                        ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
 
756
                                                        currState);
 
757
                        g2d.setComposite(LafWidgetUtilities.getAlphaComposite(monthView,
 
758
                                        SubstanceColorSchemeUtilities.getHighlightAlpha(monthView,
 
759
                                                        currState), g));
 
760
                        HighlightPainterUtils.paintHighlight(g2d, null, monthView, page,
 
761
                                        0.5f, null, currFillScheme, currBorderScheme);
 
762
                } else {
 
763
                        for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
 
764
                                        .entrySet()) {
 
765
                                float contribution = activeEntry.getValue().getContribution();
 
766
                                if (contribution == 0.0f)
 
767
                                        continue;
 
768
                                ComponentState activeState = activeEntry.getKey();
 
769
                                SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
 
770
                                                .getColorScheme(monthView,
 
771
                                                                ColorSchemeAssociationKind.HIGHLIGHT,
 
772
                                                                activeState);
 
773
                                SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
 
774
                                                .getColorScheme(monthView,
 
775
                                                                ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
 
776
                                                                activeState);
 
777
                                g2d.setComposite(LafWidgetUtilities.getAlphaComposite(
 
778
                                                monthView, SubstanceColorSchemeUtilities
 
779
                                                                .getHighlightAlpha(monthView, activeState)
 
780
                                                                * contribution, g));
 
781
                                HighlightPainterUtils.paintHighlight(g2d, null, monthView,
 
782
                                                page, 0.5f, null, fillScheme, borderScheme);
 
783
                        }
 
784
                }
 
785
                g2d.dispose();
 
786
 
 
787
                super.paintMonthHeader(g, calendar);
 
788
        }
 
789
 
 
790
        @Override
 
791
        protected void paintDayOfMonth(Graphics g, Rectangle bounds,
 
792
                        Calendar calendar, CalendarState state) {
 
793
                if (state == CalendarState.IN_MONTH || state == CalendarState.TODAY) {
 
794
                        // paint rollover / selection background
 
795
                        Graphics2D graphics = (Graphics2D) g.create();
 
796
 
 
797
                        int day = calendar.get(Calendar.DAY_OF_MONTH);
 
798
                        int month = calendar.get(Calendar.MONTH);
 
799
                        int year = calendar.get(Calendar.YEAR);
 
800
 
 
801
                        if (isToday(calendar.getTime())) {
 
802
                                graphics.setColor(monthView.getTodayBackground());
 
803
                                graphics.drawRect(bounds.x, bounds.y, bounds.width - 1,
 
804
                                                bounds.height - 1);
 
805
                        }
 
806
 
 
807
                        StateTransitionTracker dayTracker = this.dayStateTransitionMultiTracker
 
808
                                        .getTracker(new DateId(day, month, year));
 
809
                        StateTransitionTracker.ModelStateInfo modelStateInfo = (dayTracker == null) ? null
 
810
                                        : dayTracker.getModelStateInfo();
 
811
                        Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = ((modelStateInfo == null) ? null
 
812
                                        : modelStateInfo.getStateContributionMap());
 
813
                        ComponentState currState = ((modelStateInfo == null) ? getDayState(
 
814
                                        day, month, year) : modelStateInfo.getCurrModelState());
 
815
 
 
816
                        if (activeStates == null) {
 
817
                                SubstanceColorScheme currFillScheme = SubstanceColorSchemeUtilities
 
818
                                                .getColorScheme(monthView,
 
819
                                                                ColorSchemeAssociationKind.HIGHLIGHT, currState);
 
820
                                SubstanceColorScheme currBorderScheme = SubstanceColorSchemeUtilities
 
821
                                                .getColorScheme(monthView,
 
822
                                                                ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
 
823
                                                                currState);
 
824
                                graphics.setComposite(LafWidgetUtilities.getAlphaComposite(
 
825
                                                monthView, SubstanceColorSchemeUtilities
 
826
                                                                .getHighlightAlpha(monthView, currState), g));
 
827
                                HighlightPainterUtils.paintHighlight(graphics, null, monthView,
 
828
                                                bounds, 0.5f, null, currFillScheme, currBorderScheme);
 
829
                        } else {
 
830
                                for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
 
831
                                                .entrySet()) {
 
832
                                        float contribution = activeEntry.getValue()
 
833
                                                        .getContribution();
 
834
                                        if (contribution == 0.0f)
 
835
                                                continue;
 
836
                                        ComponentState activeState = activeEntry.getKey();
 
837
                                        SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
 
838
                                                        .getColorScheme(monthView,
 
839
                                                                        ColorSchemeAssociationKind.HIGHLIGHT,
 
840
                                                                        activeState);
 
841
                                        SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
 
842
                                                        .getColorScheme(
 
843
                                                                        monthView,
 
844
                                                                        ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
 
845
                                                                        activeState);
 
846
                                        graphics.setComposite(LafWidgetUtilities.getAlphaComposite(
 
847
                                                        monthView, SubstanceColorSchemeUtilities
 
848
                                                                        .getHighlightAlpha(monthView, activeState)
 
849
                                                                        * contribution, g));
 
850
                                        HighlightPainterUtils.paintHighlight(graphics, null,
 
851
                                                        monthView, bounds, 0.5f, null, fillScheme,
 
852
                                                        borderScheme);
 
853
                                }
 
854
                        }
 
855
 
 
856
                        graphics.dispose();
 
857
 
 
858
                }
 
859
                super.paintDayOfMonth(g, bounds, calendar, state);
 
860
        }
 
861
 
 
862
        /*
 
863
         * (non-Javadoc)
 
864
         * 
 
865
         * @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
 
866
         * javax.swing.JComponent)
 
867
         */
 
868
        @Override
 
869
        public void update(Graphics g, JComponent c) {
 
870
                BackgroundPaintingUtils.update(g, this.monthView, false);
 
871
                this.paint(g, c);
 
872
        }
 
873
 
 
874
        protected class SubstanceRenderingHandler extends RenderingHandler {
 
875
                @Override
 
876
                public JComponent prepareRenderingComponent(JXMonthView monthView,
 
877
                                Calendar calendar, CalendarState dayState) {
 
878
                        JComponent result = super.prepareRenderingComponent(monthView,
 
879
                                        calendar, dayState);
 
880
 
 
881
                        // System.out.println(dayState + ":" + result.getForeground());
 
882
 
 
883
                        int day = calendar.get(Calendar.DAY_OF_MONTH);
 
884
                        int month = calendar.get(Calendar.MONTH);
 
885
                        int year = calendar.get(Calendar.YEAR);
 
886
                        if (dayState == CalendarState.IN_MONTH
 
887
                                        || dayState == CalendarState.TODAY) {
 
888
                                // fix for issue 4 (custom colors on the control)
 
889
                                Color customFgColor = result.getForeground();
 
890
                                boolean isForegroundUiResource = customFgColor instanceof UIResource;
 
891
                                Color fgColor = customFgColor;
 
892
                                if (isForegroundUiResource) {
 
893
                                        if (monthView.isEnabled()) {
 
894
                                                StateTransitionTracker dayTracker = dayStateTransitionMultiTracker
 
895
                                                                .getTracker(new DateId(day, month, year));
 
896
                                                StateTransitionTracker.ModelStateInfo modelStateInfo = (dayTracker == null) ? null
 
897
                                                                : dayTracker.getModelStateInfo();
 
898
                                                Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = ((modelStateInfo == null) ? null
 
899
                                                                : modelStateInfo.getStateContributionMap());
 
900
                                                ComponentState currState = ((modelStateInfo == null) ? getDayState(
 
901
                                                                day, month, year)
 
902
                                                                : modelStateInfo.getCurrModelState());
 
903
 
 
904
                                                SubstanceColorScheme colorScheme = getColorSchemeForState(
 
905
                                                                monthView, currState);
 
906
                                                if (currState.isDisabled() || (activeStates == null)
 
907
                                                                || (activeStates.size() == 1)) {
 
908
                                                        fgColor = colorScheme.getForegroundColor();
 
909
                                                } else {
 
910
                                                        float aggrRed = 0;
 
911
                                                        float aggrGreen = 0;
 
912
                                                        float aggrBlue = 0;
 
913
 
 
914
                                                        for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : modelStateInfo
 
915
                                                                        .getStateContributionMap().entrySet()) {
 
916
                                                                ComponentState activeState = activeEntry
 
917
                                                                                .getKey();
 
918
                                                                SubstanceColorScheme scheme = getColorSchemeForState(
 
919
                                                                                monthView, activeState);
 
920
                                                                Color schemeFg = scheme.getForegroundColor();
 
921
                                                                float contribution = activeEntry.getValue()
 
922
                                                                                .getContribution();
 
923
                                                                aggrRed += schemeFg.getRed() * contribution;
 
924
                                                                aggrGreen += schemeFg.getGreen() * contribution;
 
925
                                                                aggrBlue += schemeFg.getBlue() * contribution;
 
926
                                                        }
 
927
                                                        fgColor = new Color((int) aggrRed, (int) aggrGreen,
 
928
                                                                        (int) aggrBlue);
 
929
                                                }
 
930
                                        } else {
 
931
                                                float textAlpha = SubstanceColorSchemeUtilities
 
932
                                                                .getAlpha(monthView,
 
933
                                                                                ComponentState.DISABLED_UNSELECTED);
 
934
                                                fgColor = SubstanceTextUtilities.getForegroundColor(
 
935
                                                                monthView, " ",
 
936
                                                                ComponentState.DISABLED_UNSELECTED, textAlpha);
 
937
                                        }
 
938
                                }
 
939
                                result.setForeground(fgColor);
 
940
                        }
 
941
 
 
942
                        if (dayState == CalendarState.TITLE) {
 
943
                                // month title
 
944
                                StateTransitionTracker monthTracker = monthStateTransitionMultiTracker
 
945
                                                .getTracker(new MonthId(month, year));
 
946
                                StateTransitionTracker.ModelStateInfo modelStateInfo = (monthTracker == null) ? null
 
947
                                                : monthTracker.getModelStateInfo();
 
948
                                Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = ((modelStateInfo == null) ? null
 
949
                                                : modelStateInfo.getStateContributionMap());
 
950
                                ComponentState currState = ((modelStateInfo == null) ? getMonthState(
 
951
                                                month, year)
 
952
                                                : modelStateInfo.getCurrModelState());
 
953
 
 
954
                                SubstanceColorScheme colorScheme = getColorSchemeForState(
 
955
                                                monthView, currState);
 
956
                                Color fgColor = null;
 
957
                                if (currState.isDisabled() || (activeStates == null)
 
958
                                                || (activeStates.size() == 1)) {
 
959
                                        fgColor = colorScheme.getForegroundColor();
 
960
                                } else {
 
961
                                        float aggrRed = 0;
 
962
                                        float aggrGreen = 0;
 
963
                                        float aggrBlue = 0;
 
964
 
 
965
                                        for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : modelStateInfo
 
966
                                                        .getStateContributionMap().entrySet()) {
 
967
                                                ComponentState activeState = activeEntry.getKey();
 
968
                                                SubstanceColorScheme scheme = getColorSchemeForState(
 
969
                                                                monthView, activeState);
 
970
                                                Color schemeFg = scheme.getForegroundColor();
 
971
                                                float contribution = activeEntry.getValue()
 
972
                                                                .getContribution();
 
973
                                                aggrRed += schemeFg.getRed() * contribution;
 
974
                                                aggrGreen += schemeFg.getGreen() * contribution;
 
975
                                                aggrBlue += schemeFg.getBlue() * contribution;
 
976
                                        }
 
977
                                        fgColor = new Color((int) aggrRed, (int) aggrGreen,
 
978
                                                        (int) aggrBlue);
 
979
                                }
 
980
 
 
981
                                result.setForeground(fgColor);
 
982
                        }
 
983
 
 
984
                        if (dayState == CalendarState.LEADING
 
985
                                        || dayState == CalendarState.TRAILING) {
 
986
                                float textAlpha = SubstanceColorSchemeUtilities.getAlpha(
 
987
                                                monthView, ComponentState.DISABLED_UNSELECTED);
 
988
                                result.setForeground(SubstanceTextUtilities.getForegroundColor(
 
989
                                                monthView, " ", ComponentState.DISABLED_UNSELECTED,
 
990
                                                textAlpha));
 
991
                        }
 
992
 
 
993
                        if (dayState == CalendarState.TITLE) {
 
994
                                result.setBorder(getTitleBorder());
 
995
                        }
 
996
 
 
997
                        result.setOpaque(false);
 
998
 
 
999
                        return result;
 
1000
                }
 
1001
 
 
1002
                private Border getTitleBorder() {
 
1003
                        if (monthView.isTraversable()) {
 
1004
                                IconBorder up = new IconBorder(monthUpImage,
 
1005
                                                SwingConstants.EAST, monthView.getBoxPaddingX());
 
1006
                                IconBorder down = new IconBorder(monthDownImage,
 
1007
                                                SwingConstants.WEST, monthView.getBoxPaddingX());
 
1008
                                Border compound = BorderFactory.createCompoundBorder(up, down);
 
1009
                                Border empty = BorderFactory
 
1010
                                                .createEmptyBorder(2 * monthView.getBoxPaddingY(), 0,
 
1011
                                                                2 * monthView.getBoxPaddingY(), 0);
 
1012
                                return BorderFactory.createCompoundBorder(compound, empty);
 
1013
                        }
 
1014
 
 
1015
                        return BorderFactory.createEmptyBorder(monthView.getBoxPaddingY(),
 
1016
                                        monthView.getBoxPaddingX(), monthView.getBoxPaddingY(),
 
1017
                                        monthView.getBoxPaddingX());
 
1018
                }
 
1019
        }
 
1020
 
 
1021
        private static SubstanceColorScheme getColorSchemeForState(
 
1022
                        JXMonthView monthView, ComponentState state) {
 
1023
                if (state == ComponentState.ENABLED)
 
1024
                        return SubstanceColorSchemeUtilities.getColorScheme(monthView,
 
1025
                                        state);
 
1026
                return SubstanceColorSchemeUtilities.getColorScheme(monthView,
 
1027
                                ColorSchemeAssociationKind.HIGHLIGHT, state);
 
1028
        }
 
1029
 
 
1030
        private StateTransitionTracker getDayTracker(final DateId dateId,
 
1031
                        boolean initialRollover, boolean initialSelected) {
 
1032
                StateTransitionTracker tracker = dayStateTransitionMultiTracker
 
1033
                                .getTracker(dateId);
 
1034
                if (tracker == null) {
 
1035
                        ButtonModel model = new DefaultButtonModel();
 
1036
                        model.setSelected(initialSelected);
 
1037
                        model.setRollover(initialRollover);
 
1038
                        tracker = new StateTransitionTracker(this.monthView, model);
 
1039
                        tracker.registerModelListeners();
 
1040
                        tracker.setRepaintCallback(new RepaintCallback() {
 
1041
                                @Override
 
1042
                                public TimelineCallback getRepaintCallback() {
 
1043
                                        return new DayRepaintCallback(monthView, dateId.day,
 
1044
                                                        dateId.month, dateId.year);
 
1045
                                }
 
1046
                        });
 
1047
                        dayStateTransitionMultiTracker.addTracker(dateId, tracker);
 
1048
                }
 
1049
                return tracker;
 
1050
        }
 
1051
 
 
1052
        private StateTransitionTracker getMonthTracker(final MonthId monthId,
 
1053
                        boolean initialRollover, boolean initialSelected) {
 
1054
                StateTransitionTracker tracker = monthStateTransitionMultiTracker
 
1055
                                .getTracker(monthId);
 
1056
                if (tracker == null) {
 
1057
                        ButtonModel model = new DefaultButtonModel();
 
1058
                        model.setSelected(initialSelected);
 
1059
                        model.setRollover(initialRollover);
 
1060
                        tracker = new StateTransitionTracker(this.monthView, model);
 
1061
                        tracker.registerModelListeners();
 
1062
                        tracker.setRepaintCallback(new RepaintCallback() {
 
1063
                                @Override
 
1064
                                public TimelineCallback getRepaintCallback() {
 
1065
                                        return new MonthRepaintCallback(monthView, monthId.month,
 
1066
                                                        monthId.year);
 
1067
                                }
 
1068
                        });
 
1069
                        monthStateTransitionMultiTracker.addTracker(monthId, tracker);
 
1070
                }
 
1071
                return tracker;
 
1072
        }
 
1073
}