2
* Copyright 2005-2010 Kirill Grouchnikov, based on work by
3
* Sun Microsystems, Inc. All rights reserved.
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.
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.
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
19
package org.pushingpixels.substance.swingx;
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;
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;
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;
75
* Substance-consistent UI delegate for {@link JXMonthView}.
77
* @author Kirill Grouchnikov
79
public class SubstanceMonthViewUI extends BasicMonthViewUI implements
82
* Listener for transition animations on rollovers.
84
protected DayRolloverFadeListener substanceFadeRolloverListener;
86
protected DateId rolloverDateId;
89
* Holds the list of currently selected days. Every entry is day:month:year
91
protected Set<DateId> selectedDates;
94
* Listener for transition animations on day selections.
96
protected DateSelectionListener substanceFadeSelectionListener;
98
private StateTransitionMultiTracker<DateId> dayStateTransitionMultiTracker;
100
private StateTransitionMultiTracker<MonthId> monthStateTransitionMultiTracker;
102
static class DateId implements Comparable<DateId> {
109
public DateId(int day, int month, int year) {
116
public int compareTo(DateId o) {
117
if ((this.day == o.day) && (this.month == o.month)
118
&& (this.year == o.year))
124
public boolean equals(Object obj) {
125
if (obj instanceof DateId) {
126
return this.compareTo((DateId) obj) == 0;
132
public int hashCode() {
133
return (this.day ^ (this.day >>> 32))
134
& (this.month ^ (this.month >>> 32))
135
& (this.year ^ (this.year >>> 32));
139
public String toString() {
140
return "Day " + this.day + ", Month " + this.month + ", Year "
145
static class MonthId implements Comparable<MonthId> {
150
public MonthId(int month, int year) {
156
public int compareTo(MonthId o) {
157
if ((this.month == o.month) && (this.year == o.year))
163
public boolean equals(Object obj) {
164
if (obj instanceof MonthId) {
165
return this.compareTo((MonthId) obj) == 0;
171
public int hashCode() {
172
return (this.month ^ (this.month >>> 32))
173
& (this.year ^ (this.year >>> 32));
177
public String toString() {
178
return "Month " + this.month + ", Year " + this.year;
182
public static ComponentUI createUI(JComponent comp) {
183
SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
184
return new SubstanceMonthViewUI();
188
* Creates a new UI delegate.
190
public SubstanceMonthViewUI() {
193
this.dayStateTransitionMultiTracker = new StateTransitionMultiTracker<DateId>();
194
this.monthStateTransitionMultiTracker = new StateTransitionMultiTracker<MonthId>();
195
this.selectedDates = new HashSet<DateId>();
201
* @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installDefaults()
204
protected void installDefaults() {
205
super.installDefaults();
206
BasicLookAndFeel.installColors(this.monthView,
207
"JXMonthView.background", "JXMonthView.foreground");
209
Calendar cal = this.monthView.getCalendar();
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));
224
* @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installDelegate()
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));
246
* @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#installListeners()
249
protected void installListeners() {
250
super.installListeners();
252
this.substanceFadeRolloverListener = new DayRolloverFadeListener();
253
this.monthView.addMouseMotionListener(substanceFadeRolloverListener);
254
this.monthView.addMouseListener(substanceFadeRolloverListener);
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());
263
boolean hasSelectionAnimations = !LafWidgetUtilities
264
.hasNoAnimations(monthView, AnimationFacet.SELECTION);
266
Calendar cal = monthView.getCalendar();
268
DateSelectionModel selectionModel = monthView
269
.getSelectionModel();
271
for (Iterator<DateId> selIt = selectedDates.iterator(); selIt
273
DateId currSelected = selIt.next();
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()))
281
if (hasSelectionAnimations) {
282
StateTransitionTracker tracker = getDayTracker(
283
currSelected, getDayState(currSelected.day,
284
currSelected.month, currSelected.year)
286
ComponentStateFacet.ROLLOVER),
288
tracker.getModel().setSelected(false);
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))
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);
310
selectedDates.add(newlySelectedDate);
314
this.monthView.getSelectionModel().addDateSelectionListener(
315
this.substanceFadeSelectionListener);
321
* @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#uninstallListeners()
324
protected void uninstallListeners() {
325
this.monthView.getSelectionModel().removeDateSelectionListener(
326
this.substanceFadeSelectionListener);
327
this.substanceFadeSelectionListener = null;
329
this.monthView.removeMouseListener(this.substanceFadeRolloverListener);
331
.removeMouseMotionListener(this.substanceFadeRolloverListener);
332
this.substanceFadeRolloverListener = null;
334
super.uninstallListeners();
340
* @see org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#uninstallDefaults()
343
protected void uninstallDefaults() {
344
this.selectedDates.clear();
346
super.uninstallDefaults();
353
* org.jvnet.substance.utils.Trackable#isInside(java.awt.event.MouseEvent)
355
public boolean isInside(MouseEvent me) {
356
// The entire component area is considered as trackable for rollover
362
public StateTransitionTracker getTransitionTracker() {
367
* Listener for fade animations on month view rollovers.
369
* @author Kirill Grouchnikov
371
private class DayRolloverFadeListener implements MouseListener,
372
MouseMotionListener {
373
public void mouseClicked(MouseEvent e) {
376
public void mouseEntered(MouseEvent e) {
379
public void mousePressed(MouseEvent e) {
382
public void mouseReleased(MouseEvent e) {
385
public void mouseExited(MouseEvent e) {
388
// System.out.println("Nulling RO index");
389
resetRolloverIndex();
392
public void mouseMoved(MouseEvent e) {
393
if (!monthView.isEnabled())
398
public void mouseDragged(MouseEvent e) {
399
// if (SubstanceCoreUtilities.toBleedWatermark(list))
402
if (!monthView.isEnabled())
408
* Handles various mouse move events and initiates the fade animation if
414
private void handleMove(MouseEvent e) {
415
boolean fadeAllowed = AnimationConfigurationManager.getInstance()
416
.isAnimationAllowed(AnimationFacet.ROLLOVER, monthView);
420
resetRolloverIndex();
424
Date matchingDay = monthView.getDayAtLocation(e.getX(), e.getY());
425
if (matchingDay == null) {
428
// System.out.println("Nulling RO index");
429
resetRolloverIndex();
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
438
resetRolloverIndex();
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);
446
DateId dateId = new DateId(roIndexDay, roIndexMonth,
448
// check if this is the same index
449
if (dateId.equals(rolloverDateId))
453
boolean isDifferentMonth = (rolloverDateId == null)
454
|| (rolloverDateId.month != roIndexMonth)
455
|| (rolloverDateId.year != roIndexYear);
456
if (isDifferentMonth) {
460
rolloverDateId = dateId;
462
StateTransitionTracker dayTracker = getDayTracker(dateId,
463
false, getDayState(roIndexDay, roIndexMonth,
464
roIndexYear).isFacetActive(
465
ComponentStateFacet.SELECTION));
466
dayTracker.getModel().setRollover(true);
468
if (isDifferentMonth) {
469
StateTransitionTracker monthTracker = getMonthTracker(
470
new MonthId(roIndexMonth, roIndexYear), false,
471
getMonthState(roIndexMonth, roIndexYear)
473
ComponentStateFacet.SELECTION));
474
monthTracker.getModel().setRollover(true);
475
// System.out.println("Fading in " + rolloverMonthId +
477
// + rolloverYearId);
479
// System.out.println("Setting RO index to " + roIndex);
485
* Initiates the fade out effect on the specific day.
487
private void fadeOutDay() {
488
if (rolloverDateId == null)
491
StateTransitionTracker tracker = getDayTracker(rolloverDateId,
492
true, getDayState(rolloverDateId.day, rolloverDateId.month,
493
rolloverDateId.year).isFacetActive(
494
ComponentStateFacet.SELECTION));
495
tracker.getModel().setRollover(false);
499
* Initiates the fade out effect on the specific month.
501
private void fadeOutMonth() {
502
if (rolloverDateId == null)
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);
514
* Repaints a single month during the fade animation cycle.
516
* @author Kirill Grouchnikov
518
protected class MonthRepaintCallback extends
519
UIThreadTimelineCallbackAdapter {
521
* Associated control.
523
protected JXMonthView monthView;
526
* Associated (animated) month index.
528
protected int monthIndex;
530
protected int yearIndex;
533
* Creates a new animation repaint callback.
536
* Associated control.
538
* Associated (animated) month index.
540
public MonthRepaintCallback(JXMonthView monthView, int monthIndex,
542
this.monthView = monthView;
543
this.monthIndex = monthIndex;
544
this.yearIndex = yearIndex;
548
public void onTimelinePulse(float durationFraction,
549
float timelinePosition) {
554
public void onTimelineStateChanged(TimelineState oldState,
555
TimelineState newState, float durationFraction,
556
float timelinePosition) {
561
* Repaints the associated cell.
563
private void repaintCell() {
564
SwingUtilities.invokeLater(new Runnable() {
566
if (monthView != SubstanceMonthViewUI.this.monthView) {
567
// may happen if the LAF was switched in the meantime
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);
585
* Repaints a single day during the fade animation cycle.
587
* @author Kirill Grouchnikov
589
protected class DayRepaintCallback extends UIThreadTimelineCallbackAdapter {
591
* Associated control.
593
protected JXMonthView monthView;
596
* Associated (animated) day index.
598
protected int dayIndex;
600
protected int monthIndex;
602
protected int yearIndex;
605
* Creates a new animation repaint callback.
608
* Associated control.
610
* Associated (animated) day index.
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;
621
public void onTimelinePulse(float durationFraction,
622
float timelinePosition) {
627
public void onTimelineStateChanged(TimelineState oldState,
628
TimelineState newState, float durationFraction,
629
float timelinePosition) {
634
* Repaints the associated cell.
636
private void repaintCell() {
637
SwingUtilities.invokeLater(new Runnable() {
639
if (monthView != SubstanceMonthViewUI.this.monthView) {
640
// may happen if the LAF was switched in the meantime
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);
648
Rectangle dayBounds = getDayBounds(cal.getTime());
650
if (dayBounds != null) {
651
DayRepaintCallback.this.monthView.repaint(dayBounds);
658
private ComponentState getDayState(int dayIndex, int monthIndex,
660
DateId dateId = new DateId(dayIndex, monthIndex, yearIndex);
661
boolean isEnabled = this.monthView.isEnabled();
662
StateTransitionTracker tracker = this.dayStateTransitionMultiTracker
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);
669
ComponentState fromTracker = tracker.getModelStateInfo()
670
.getCurrModelState();
671
return ComponentState.getState(isEnabled, fromTracker
672
.isFacetActive(ComponentStateFacet.ROLLOVER), fromTracker
673
.isFacetActive(ComponentStateFacet.SELECTION));
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);
688
ComponentState fromTracker = tracker.getModelStateInfo()
689
.getCurrModelState();
690
return ComponentState.getState(isEnabled, fromTracker
691
.isFacetActive(ComponentStateFacet.ROLLOVER), fromTracker
692
.isFacetActive(ComponentStateFacet.SELECTION));
697
* Resets the rollover index.
699
public void resetRolloverIndex() {
700
this.rolloverDateId = null;
707
* org.jdesktop.swingx.plaf.basic.BasicMonthViewUI#createRenderingHandler()
710
protected RenderingHandler createRenderingHandler() {
712
return new SubstanceRenderingHandler();
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);
721
Graphics2D g2d = (Graphics2D) g.create();
723
ComponentState componentState = monthView.isEnabled() ? ComponentState.ENABLED
724
: ComponentState.DISABLED_UNSELECTED;
725
float fillAlpha = SubstanceColorSchemeUtilities.getAlpha(monthView,
727
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(monthView,
729
SubstanceColorScheme bgFillScheme = SubstanceColorSchemeUtilities
730
.getColorScheme(monthView,
731
ColorSchemeAssociationKind.HIGHLIGHT, componentState);
732
SubstanceColorScheme bgBorderScheme = SubstanceColorSchemeUtilities
733
.getColorScheme(monthView,
734
ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
736
HighlightPainterUtils.paintHighlight(g2d, null, monthView, page, 0.5f,
737
null, bgFillScheme, bgBorderScheme);
738
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(monthView, g));
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());
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,
757
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(monthView,
758
SubstanceColorSchemeUtilities.getHighlightAlpha(monthView,
760
HighlightPainterUtils.paintHighlight(g2d, null, monthView, page,
761
0.5f, null, currFillScheme, currBorderScheme);
763
for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
765
float contribution = activeEntry.getValue().getContribution();
766
if (contribution == 0.0f)
768
ComponentState activeState = activeEntry.getKey();
769
SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
770
.getColorScheme(monthView,
771
ColorSchemeAssociationKind.HIGHLIGHT,
773
SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
774
.getColorScheme(monthView,
775
ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
777
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(
778
monthView, SubstanceColorSchemeUtilities
779
.getHighlightAlpha(monthView, activeState)
781
HighlightPainterUtils.paintHighlight(g2d, null, monthView,
782
page, 0.5f, null, fillScheme, borderScheme);
787
super.paintMonthHeader(g, calendar);
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();
797
int day = calendar.get(Calendar.DAY_OF_MONTH);
798
int month = calendar.get(Calendar.MONTH);
799
int year = calendar.get(Calendar.YEAR);
801
if (isToday(calendar.getTime())) {
802
graphics.setColor(monthView.getTodayBackground());
803
graphics.drawRect(bounds.x, bounds.y, bounds.width - 1,
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());
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,
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);
830
for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
832
float contribution = activeEntry.getValue()
834
if (contribution == 0.0f)
836
ComponentState activeState = activeEntry.getKey();
837
SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
838
.getColorScheme(monthView,
839
ColorSchemeAssociationKind.HIGHLIGHT,
841
SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
844
ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
846
graphics.setComposite(LafWidgetUtilities.getAlphaComposite(
847
monthView, SubstanceColorSchemeUtilities
848
.getHighlightAlpha(monthView, activeState)
850
HighlightPainterUtils.paintHighlight(graphics, null,
851
monthView, bounds, 0.5f, null, fillScheme,
859
super.paintDayOfMonth(g, bounds, calendar, state);
865
* @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
866
* javax.swing.JComponent)
869
public void update(Graphics g, JComponent c) {
870
BackgroundPaintingUtils.update(g, this.monthView, false);
874
protected class SubstanceRenderingHandler extends RenderingHandler {
876
public JComponent prepareRenderingComponent(JXMonthView monthView,
877
Calendar calendar, CalendarState dayState) {
878
JComponent result = super.prepareRenderingComponent(monthView,
881
// System.out.println(dayState + ":" + result.getForeground());
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(
902
: modelStateInfo.getCurrModelState());
904
SubstanceColorScheme colorScheme = getColorSchemeForState(
905
monthView, currState);
906
if (currState.isDisabled() || (activeStates == null)
907
|| (activeStates.size() == 1)) {
908
fgColor = colorScheme.getForegroundColor();
914
for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : modelStateInfo
915
.getStateContributionMap().entrySet()) {
916
ComponentState activeState = activeEntry
918
SubstanceColorScheme scheme = getColorSchemeForState(
919
monthView, activeState);
920
Color schemeFg = scheme.getForegroundColor();
921
float contribution = activeEntry.getValue()
923
aggrRed += schemeFg.getRed() * contribution;
924
aggrGreen += schemeFg.getGreen() * contribution;
925
aggrBlue += schemeFg.getBlue() * contribution;
927
fgColor = new Color((int) aggrRed, (int) aggrGreen,
931
float textAlpha = SubstanceColorSchemeUtilities
933
ComponentState.DISABLED_UNSELECTED);
934
fgColor = SubstanceTextUtilities.getForegroundColor(
936
ComponentState.DISABLED_UNSELECTED, textAlpha);
939
result.setForeground(fgColor);
942
if (dayState == CalendarState.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(
952
: modelStateInfo.getCurrModelState());
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();
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()
973
aggrRed += schemeFg.getRed() * contribution;
974
aggrGreen += schemeFg.getGreen() * contribution;
975
aggrBlue += schemeFg.getBlue() * contribution;
977
fgColor = new Color((int) aggrRed, (int) aggrGreen,
981
result.setForeground(fgColor);
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,
993
if (dayState == CalendarState.TITLE) {
994
result.setBorder(getTitleBorder());
997
result.setOpaque(false);
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);
1015
return BorderFactory.createEmptyBorder(monthView.getBoxPaddingY(),
1016
monthView.getBoxPaddingX(), monthView.getBoxPaddingY(),
1017
monthView.getBoxPaddingX());
1021
private static SubstanceColorScheme getColorSchemeForState(
1022
JXMonthView monthView, ComponentState state) {
1023
if (state == ComponentState.ENABLED)
1024
return SubstanceColorSchemeUtilities.getColorScheme(monthView,
1026
return SubstanceColorSchemeUtilities.getColorScheme(monthView,
1027
ColorSchemeAssociationKind.HIGHLIGHT, state);
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() {
1042
public TimelineCallback getRepaintCallback() {
1043
return new DayRepaintCallback(monthView, dateId.day,
1044
dateId.month, dateId.year);
1047
dayStateTransitionMultiTracker.addTracker(dateId, tracker);
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() {
1064
public TimelineCallback getRepaintCallback() {
1065
return new MonthRepaintCallback(monthView, monthId.month,
1069
monthStateTransitionMultiTracker.addTracker(monthId, tracker);