001: /*
002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of Substance Kirill Grouchnikov nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030: package org.jvnet.substance;
031:
032: import java.beans.PropertyChangeEvent;
033: import java.beans.PropertyChangeListener;
034: import java.util.HashMap;
035: import java.util.Map;
036:
037: import javax.swing.*;
038: import javax.swing.border.Border;
039: import javax.swing.plaf.ComponentUI;
040: import javax.swing.plaf.UIResource;
041: import javax.swing.plaf.basic.BasicButtonListener;
042:
043: import org.jvnet.lafwidget.animation.*;
044: import org.jvnet.substance.theme.SubstanceTheme;
045: import org.jvnet.substance.utils.*;
046:
047: /**
048: * UI for check boxes in <b>Substance</b> look and feel.
049: *
050: * @author Kirill Grouchnikov
051: */
052: public class SubstanceCheckBoxUI extends SubstanceRadioButtonUI {
053: /**
054: * Prefix for the checkbox-related properties in the {@link UIManager}.
055: */
056: private final static String propertyPrefix = "CheckBox" + ".";
057:
058: /**
059: * Listener for fade animations.
060: */
061: protected FadeStateListener substanceFadeStateListener;
062:
063: /**
064: * Property change listener. Listens on changes to
065: * {@link AbstractButton#MODEL_CHANGED_PROPERTY} property.
066: */
067: protected PropertyChangeListener substancePropertyListener;
068:
069: /*
070: * (non-Javadoc)
071: *
072: * @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
073: */
074: public static ComponentUI createUI(JComponent b) {
075: return new SubstanceCheckBoxUI((JToggleButton) b);
076: }
077:
078: /**
079: * Hash map for storing icons.
080: */
081: private static Map<String, Icon> icons = new HashMap<String, Icon>();
082:
083: /**
084: * Simple constructor.
085: *
086: * @param button
087: * The associated button.
088: */
089: private SubstanceCheckBoxUI(JToggleButton button) {
090: super (button);
091: button.setRolloverEnabled(true);
092: }
093:
094: /*
095: * (non-Javadoc)
096: *
097: * @see javax.swing.plaf.basic.BasicRadioButtonUI#getPropertyPrefix()
098: */
099: @Override
100: protected String getPropertyPrefix() {
101: return propertyPrefix;
102: }
103:
104: /*
105: * (non-Javadoc)
106: *
107: * @see javax.swing.plaf.basic.BasicButtonUI#installListeners(javax.swing.AbstractButton)
108: */
109: @Override
110: protected void installListeners(final AbstractButton b) {
111: super .installListeners(b);
112: this .substanceFadeStateListener = new FadeStateListener(b, b
113: .getModel(), SubstanceCoreUtilities.getFadeCallback(b,
114: false));
115: this .substanceFadeStateListener.registerListeners();
116:
117: this .substancePropertyListener = new PropertyChangeListener() {
118: public void propertyChange(PropertyChangeEvent evt) {
119: if (AbstractButton.MODEL_CHANGED_PROPERTY.equals(evt
120: .getPropertyName())) {
121: if (substanceFadeStateListener != null)
122: substanceFadeStateListener
123: .unregisterListeners();
124: substanceFadeStateListener = new FadeStateListener(
125: b, b.getModel(), SubstanceCoreUtilities
126: .getFadeCallback(b, false));
127: substanceFadeStateListener.registerListeners();
128: }
129: }
130: };
131: b.addPropertyChangeListener(this .substancePropertyListener);
132: }
133:
134: /*
135: * (non-Javadoc)
136: *
137: * @see javax.swing.plaf.basic.BasicButtonUI#uninstallListeners(javax.swing.AbstractButton)
138: */
139: @Override
140: protected void uninstallListeners(AbstractButton b) {
141: this .substanceFadeStateListener.unregisterListeners();
142: this .substanceFadeStateListener = null;
143:
144: b.removePropertyChangeListener(this .substancePropertyListener);
145: this .substancePropertyListener = null;
146:
147: super .uninstallListeners(b);
148: }
149:
150: /*
151: * (non-Javadoc)
152: *
153: * @see org.jvnet.substance.SubstanceRadioButtonUI#installDefaults(javax.swing.AbstractButton)
154: */
155: @Override
156: protected void installDefaults(AbstractButton b) {
157: super .installDefaults(b);
158: Border border = b.getBorder();
159: if (border == null || border instanceof UIResource) {
160: b.setBorder(SubstanceSizeUtils
161: .getCheckBoxBorder(SubstanceSizeUtils
162: .getComponentFontSize(b)));
163: }
164: }
165:
166: /**
167: * Resets image maps (used when setting new theme).
168: *
169: * @see SubstanceLookAndFeel#setCurrentTheme(String)
170: * @see SubstanceLookAndFeel#setCurrentTheme(SubstanceTheme)
171: */
172: public static synchronized void reset() {
173: SubstanceCheckBoxUI.icons.clear();
174: }
175:
176: /**
177: * Returns the icon that matches the current and previous states of the
178: * checkbox.
179: *
180: * @param button
181: * Button (should be {@link JCheckBox}).
182: * @param currState
183: * Current state of the checkbox.
184: * @param prevState
185: * Previous state of the checkbox.
186: * @return Matching icon.
187: */
188: private static synchronized Icon getIcon(JToggleButton button,
189: ComponentState currState, ComponentState prevState) {
190: // check if fading
191: float checkMarkVisibility = currState
192: .isKindActive(FadeKind.SELECTION) ? 10 : 0;
193: boolean isCheckMarkFadingOut = false;
194:
195: boolean isTableRenderer = button instanceof SubstanceDefaultTableCellRenderer.BooleanRenderer;
196: // SubstanceTheme theme = SubstanceThemeUtilities
197: // .getTheme(button)
198: // .getTheme(button, currState,
199: // isTableRenderer && currState == ComponentState.SELECTED);
200: SubstanceTheme theme = SubstanceThemeUtilities.getTheme(button,
201: currState, isTableRenderer
202: && currState == ComponentState.SELECTED);
203: SubstanceTheme theme2 = SubstanceThemeUtilities.getTheme(
204: button, prevState, isTableRenderer
205: && currState == ComponentState.SELECTED);
206: // SubstanceTheme theme2 = SubstanceThemeUtilities
207: // .getTheme(button)
208: // .getTheme(button, prevState,
209: // isTableRenderer && prevState == ComponentState.SELECTED);
210: float cyclePos = 0;
211: FadeState fadeState = SubstanceFadeUtilities.getFadeState(
212: button, FadeKind.SELECTION, FadeKind.ROLLOVER,
213: FadeKind.PRESS);
214: if (fadeState != null) {
215: cyclePos = fadeState.getFadePosition();
216: if (fadeState.isFadingIn())
217: cyclePos = 10 - cyclePos;
218: if (fadeState.fadeKind == FadeKind.SELECTION) {
219: checkMarkVisibility = fadeState.getFadePosition();
220: isCheckMarkFadingOut = !fadeState.isFadingIn();
221: }
222: }
223:
224: // System.out.println(prevState.name() + ":" + theme.getDisplayName()
225: // + " -> " + currState.name() + ":" + theme2.getDisplayName()
226: // + " at " + cyclePos);
227:
228: int checkMarkSize = SubstanceSizeUtils
229: .getCheckBoxMarkSize(SubstanceSizeUtils
230: .getComponentFontSize(button));
231: String key = checkMarkSize + ":" + currState.name() + ":"
232: + prevState.name() + ":" + theme.getDisplayName() + ":"
233: + theme2.getDisplayName() + ":" + cyclePos + ":"
234: + checkMarkVisibility + ":" + isCheckMarkFadingOut;
235:
236: Icon result = null;// SubstanceCheckBoxUI.icons.get(key);
237: if (result != null)
238: return result;
239: result = new ImageIcon(SubstanceImageCreator.getCheckBox(
240: button, checkMarkSize, currState, theme, theme2,
241: cyclePos, checkMarkVisibility / 10.f,
242: isCheckMarkFadingOut));
243:
244: SubstanceCheckBoxUI.icons.put(key, result);
245: return result;
246: }
247:
248: /*
249: * (non-Javadoc)
250: *
251: * @see javax.swing.plaf.basic.BasicButtonUI#createButtonListener(javax.swing.AbstractButton)
252: */
253: @Override
254: protected BasicButtonListener createButtonListener(AbstractButton b) {
255: return new RolloverButtonListener(b);
256: }
257:
258: /*
259: * (non-Javadoc)
260: *
261: * @see javax.swing.plaf.basic.BasicRadioButtonUI#getDefaultIcon()
262: */
263: @Override
264: public Icon getDefaultIcon() {
265: ButtonModel model = this .button.getModel();
266: ComponentState currState = ComponentState.getState(model,
267: this .button);
268: ComponentState prevState = SubstanceCoreUtilities
269: .getPrevComponentState(this .button);
270: return SubstanceCheckBoxUI.getIcon(this .button, currState,
271: prevState);
272: }
273:
274: /**
275: * Returns memory usage string.
276: *
277: * @return Memory usage string.
278: */
279: public static String getMemoryUsage() {
280: StringBuffer sb = new StringBuffer();
281: sb.append("SubstanceCheckBox: \n");
282: sb.append("\t" + SubstanceCheckBoxUI.icons.size() + " icons");
283: return sb.toString();
284: }
285: }
|