/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.viewers; import java.util.Iterator; import java.util.SortedMap; import java.util.TreeMap; import java.util.Map.Entry; /** * @author Frank Shaka * */ public abstract class AbstractSnapSliderContentProvider implements ISliderContentProvider { protected static final double DEFAULT_TOLERANCE = 0.015; private static class SnapData { Object value; double positiveTolerance; double negativeTolerance; public SnapData(Object value, double positiveTolerance, double negativeTolerance) { super(); this.value = value; this.positiveTolerance = positiveTolerance; this.negativeTolerance = negativeTolerance; } } private SortedMap<Double, SnapData> snaps = new TreeMap<Double, SnapData>(); protected void addSnap(double ratio, Object value) { addSnap(ratio, value, DEFAULT_TOLERANCE, -DEFAULT_TOLERANCE); } /** * * @param ratio * @param value * @param positiveTolerance * a positive value * @param negativeTolerance * a negative value */ protected void addSnap(double ratio, Object value, double positiveTolerance, double negativeTolerance) { snaps.put(Double.valueOf(ratio), new SnapData(value, positiveTolerance, negativeTolerance)); } protected void addSnap(double ratio, Object value, double tolerance) { addSnap(ratio, value, tolerance, -tolerance); } protected void removeSnap(double ratio) { snaps.remove(Double.valueOf(ratio)); } protected void clearSnaps() { snaps.clear(); } /* * (non-Javadoc) * * @see * org.xmind.ui.viewers.ISliderContentProvider#getRatio(java.lang.Object, * java.lang.Object) */ public double getRatio(Object input, Object value) { Double ratio = checkSnappedRatio(value); if (ratio != null) return ratio.doubleValue(); return getOtherRatio(input, value); } protected Double checkSnappedRatio(Object value) { if (value != null) { for (Entry<Double, SnapData> entry : snaps.entrySet()) { if (value.equals(entry.getValue().value)) { return entry.getKey(); } } } return null; } protected abstract double getOtherRatio(Object input, Object value); /* * (non-Javadoc) * * @see * org.xmind.ui.viewers.ISliderContentProvider#getValue(java.lang.Object, * double) */ public Object getValue(Object input, double ratio) { Object value = checkSnappedValue(ratio); if (value != null) return value; return getOtherValue(input, ratio); } /** * @param input * @param value * @return */ protected abstract Object getOtherValue(Object input, double ratio); /** * @param ratio * @return */ protected Object checkSnappedValue(double ratio) { Iterator<Entry<Double, SnapData>> it = snaps.entrySet().iterator(); Entry<Double, SnapData> next = it.hasNext() ? it.next() : null; if (next == null) return null; Entry<Double, SnapData> prev = null; Entry<Double, SnapData> current = null; do { prev = current; current = next; next = it.hasNext() ? it.next() : null; if (isSnapped(ratio, current.getKey().doubleValue(), current .getValue().positiveTolerance, current.getValue().negativeTolerance, prev == null ? null : prev.getKey(), next == null ? null : next .getKey())) { return current.getValue().value; } } while (next != null); return null; } /** * @param r0 * @param r1 * @param r2 * @return */ private boolean isSnapped(double r, double r0, double t1, double t2, Double r1, Double r2) { double min = Math.max(r0 + t2, r1 == null ? 0 : r1.doubleValue()); double max = Math.min(r0 + t1, r2 == null ? 1 : r2.doubleValue()); return r == r0 || (r > min && r < max); } }