001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.print.impl.util;
042:
043: import java.awt.event.ActionEvent;
044: import java.awt.event.ActionListener;
045:
046: import javax.swing.AbstractAction;
047: import javax.swing.ActionMap;
048: import javax.swing.InputMap;
049: import javax.swing.JComboBox;
050: import javax.swing.KeyStroke;
051: import javax.swing.text.JTextComponent;
052: import static org.netbeans.modules.print.impl.util.UI.*;
053:
054: /**
055: * @author Vladimir Yaroslavskiy
056: * @version 2006.03.13
057: */
058: public final class Percent extends JComboBox implements ActionListener {
059:
060: public interface Listener {
061:
062: /**
063: * Returns custom value (e.g. fit to page, fit to width).
064: * @return custom value
065: */
066: double getCustomValue(int index);
067:
068: /**
069: * Calls when value is changed.
070: * @param value new value
071: * @param index new index
072: */
073: void valueChanged(double value, int index);
074:
075: /**
076: * Calls when value is invalid.
077: * @param value invalid value
078: */
079: void invalidValue(String value);
080: }
081:
082: public Percent(Listener listener, double initValue, int[] values,
083: final int defaultCustomIndex, String[] customs,
084: String toolTip) {
085: //out("<New> Percent: " + initValue);
086: for (int value : values) {
087: addItem(value + PERCENT);
088: }
089: if (customs != null) {
090: for (String custom : customs) {
091: addItem(custom);
092: }
093: }
094: setToolTipText(toolTip);
095:
096: setEditable(true);
097: myCustoms = customs;
098: myListener = listener;
099:
100: JTextComponent editor = (JTextComponent) getEditor()
101: .getEditorComponent();
102: InputMap inputMap = editor.getInputMap();
103: ActionMap actionMap = editor.getActionMap();
104:
105: inputMap.put(KeyStroke.getKeyStroke('+'), INCREASE);
106: inputMap.put(KeyStroke.getKeyStroke('='), INCREASE);
107: inputMap.put(KeyStroke.getKeyStroke('-'), DECREASE);
108: inputMap.put(KeyStroke.getKeyStroke('_'), DECREASE);
109: inputMap.put(KeyStroke.getKeyStroke('/'), NORMAL);
110: inputMap.put(KeyStroke.getKeyStroke('*'), CUSTOM);
111:
112: actionMap.put(INCREASE, new AbstractAction() {
113: public void actionPerformed(ActionEvent event) {
114: increaseValue();
115: }
116: });
117: actionMap.put(DECREASE, new AbstractAction() {
118: public void actionPerformed(ActionEvent event) {
119: decreaseValue();
120: }
121: });
122: actionMap.put(NORMAL, new AbstractAction() {
123: public void actionPerformed(ActionEvent event) {
124: normalValue();
125: }
126: });
127: actionMap.put(CUSTOM, new AbstractAction() {
128: public void actionPerformed(ActionEvent event) {
129: customValue(defaultCustomIndex);
130: }
131: });
132: addActionListener(this );
133: setValue(initValue);
134: selectValue();
135: }
136:
137: private void selectValue() {
138: String text = getEditorItem();
139:
140: for (int i = 0; i < getItemCount(); i++) {
141: if (text.equals(getItemAt(i))) {
142: setSelectedIndex(i);
143: }
144: }
145: }
146:
147: public boolean isCustomValue() {
148: return getCustomIndex(getEditorItem()) != -1;
149: }
150:
151: public String getEditorItem() {
152: return getEditor().getItem().toString();
153: }
154:
155: public void actionPerformed(ActionEvent event) {
156: //out();
157: String value = getEditorItem();
158: //out("Action: " + value);
159: int k = getCustomIndex(value);
160:
161: if (k != -1) {
162: //out(" it is custom");
163: valueChanged(getCustomValue(k), k);
164: return;
165: }
166: double percent = parsePercent(value);
167:
168: if (isValid(percent)) {
169: //out(" it's valid value");
170: int i = getCustomIndex(percent);
171:
172: if (i != -1) {
173: setValue(percent, i);
174: } else {
175: valueChanged(percent, i);
176: }
177: } else {
178: //out(" it's invalid value");
179: myListener.invalidValue(value);
180: //out(" restore.");
181: setText(myCurrentText);
182: }
183: }
184:
185: private int getCustomIndex(String value) {
186: if (myCustoms == null) {
187: return -1;
188: }
189: for (int i = 0; i < myCustoms.length; i++) {
190: if (myCustoms[i].equals(value)) {
191: return i;
192: }
193: }
194: return -1;
195: }
196:
197: public double getValue() {
198: return myCurrentValue;
199: }
200:
201: public void increaseValue() {
202: if (myCurrentValue < THRESHOLD) {
203: setValue(myCurrentValue + SUBTRAHEND);
204: } else {
205: setValue(myCurrentValue * FACTOR);
206: }
207: }
208:
209: public void decreaseValue() {
210: if (myCurrentValue > THRESHOLD) {
211: setValue(myCurrentValue / FACTOR);
212: } else {
213: setValue(myCurrentValue - SUBTRAHEND);
214: }
215: }
216:
217: public void normalValue() {
218: setValue(1.0);
219: }
220:
221: public void customValue(int index) {
222: setValue(getCustomValue(index), index);
223: }
224:
225: private void setValue(double value) {
226: //out("SET value: " + value);
227: setValue(value, getCustomIndex(value));
228: }
229:
230: private void setValue(double value, int index) {
231: //out(" set value: " + value + " " + index);
232: String text = valueChanged(value, index);
233:
234: if (text != null) {
235: setText(text);
236: }
237: }
238:
239: private String valueChanged(double value, int index) {
240: boolean isCustomValue = index != -1;
241: //out(" value changed: " + value + " " + isCustomValue);
242:
243: if (!isCustomValue && !isValid(value)) {
244: //out(" it's not valid value");
245: return null;
246: }
247: myCurrentValue = value;
248: //out("myCurrentValue: " + myCurrentValue);
249:
250: if (isCustomValue && myCustoms != null) {
251: myCurrentText = myCustoms[index];
252: } else {
253: myCurrentText = getPercent(value);
254: }
255: //out("myCurrentText: " + myCurrentText);
256: myListener.valueChanged(value, index);
257:
258: return myCurrentText;
259: }
260:
261: private void setText(String text) {
262: getEditor().setItem(text);
263: }
264:
265: private int getCustomIndex(double value) {
266: if (myCustoms == null) {
267: return -1;
268: }
269: //out("-- " + getPercent(value) + " " + getPercent(getCustomValue()));
270: for (int i = 0; i < myCustoms.length; i++) {
271: if (getPercent(value).equals(getPercent(getCustomValue(i)))) {
272: return i;
273: }
274: }
275: return -1;
276: }
277:
278: private boolean isValid(double value) {
279: //out("is valid: " + value);
280: return MIN_VALUE <= value && value <= MAX_VALUE;
281: }
282:
283: private double getCustomValue(int index) {
284: return myListener.getCustomValue(index);
285: }
286:
287: private double parsePercent(String text) {
288: String value = text;
289:
290: if (value.endsWith(PERCENT)) {
291: value = value.substring(0, value.length() - 1);
292: }
293: return getInt(value.trim()) / YUZ;
294: }
295:
296: private String getPercent(double value) {
297: return (int) Math.round(YUZ * value) + PERCENT;
298: }
299:
300: public static double getZoomFactor(double zoom, double defaultValue) {
301: if (0 < zoom && zoom <= MAX_VALUE) {
302: return zoom;
303: }
304: return defaultValue;
305: }
306:
307: public static int getZoomWidth(double zoom, int defaultValue) {
308: if (BOUND_1 <= zoom && zoom < BOUND_2) {
309: return round(zoom - BOUND_1);
310: }
311: return defaultValue;
312: }
313:
314: public static int getZoomHeight(double zoom, int defaultValue) {
315: if (BOUND_2 <= zoom) {
316: return round(zoom - BOUND_2);
317: }
318: return defaultValue;
319: }
320:
321: public static boolean isZoomFactor(double zoom) {
322: return zoom < BOUND_1;
323: }
324:
325: public static boolean isZoomWidth(double zoom) {
326: return BOUND_1 <= zoom && zoom < BOUND_2;
327: }
328:
329: public static boolean isZoomHeight(double zoom) {
330: return BOUND_2 <= zoom;
331: }
332:
333: public static boolean isZoomPage(double zoom) {
334: return zoom == 0.0;
335: }
336:
337: public static double createZoomWidth(double zoom) {
338: return BOUND_1 + zoom;
339: }
340:
341: public static double createZoomHeight(double zoom) {
342: return BOUND_2 + zoom;
343: }
344:
345: private Listener myListener;
346: private String[] myCustoms;
347: private String myCurrentText;
348: private double myCurrentValue;
349:
350: private static final int BOUND_1 = 1000;
351: private static final int BOUND_2 = 2000;
352:
353: private static final double FACTOR = 1.05;
354: private static final double THRESHOLD = 0.2;
355: private static final double SUBTRAHEND = 0.01;
356: private static final double MIN_VALUE = 0.01;
357: private static final double MAX_VALUE = 15.0;
358:
359: private static final String CUSTOM = "custom"; // NOI18N
360: private static final String NORMAL = "normal"; // NOI18N
361: private static final String INCREASE = "increase"; // NOI18N
362: private static final String DECREASE = "decrease"; // NOI18N
363:
364: private static final double YUZ = 100.0;
365: private static final String PERCENT = "%"; // NOI18N
366: }
|