// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.history; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.Adjustable; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.HashMap; import java.util.Observable; import java.util.Observer; import javax.swing.JCheckBox; import org.openstreetmap.josm.tools.CheckParameterUtil; /** * Synchronizes scrollbar adjustments between a set of * {@link Adjustable}s. Whenever the adjustment of one of * the registerd Adjustables is updated the adjustment of * the other registered Adjustables is adjusted too. * */ public class AdjustmentSynchronizer implements AdjustmentListener { private final ArrayList synchronizedAdjustables; private final HashMap enabledMap; private final Observable observable; public AdjustmentSynchronizer() { synchronizedAdjustables = new ArrayList(); enabledMap = new HashMap(); observable = new Observable(); } /** * registers an {@link Adjustable} for participation in synchronized * scrolling. * * @param adjustable the adjustable */ public void participateInSynchronizedScrolling(Adjustable adjustable) { if (adjustable == null) return; if (synchronizedAdjustables.contains(adjustable)) return; synchronizedAdjustables.add(adjustable); setParticipatingInSynchronizedScrolling(adjustable, true); adjustable.addAdjustmentListener(this); } /** * event handler for {@link AdjustmentEvent}s * */ public void adjustmentValueChanged(AdjustmentEvent e) { if (! enabledMap.get(e.getAdjustable())) return; for (Adjustable a : synchronizedAdjustables) { if (a != e.getAdjustable() && isParticipatingInSynchronizedScrolling(a)) { a.setValue(e.getValue()); } } } /** * sets whether adjustable participates in adjustment synchronization * or not * * @param adjustable the adjustable */ protected void setParticipatingInSynchronizedScrolling(Adjustable adjustable, boolean isParticipating) { CheckParameterUtil.ensureParameterNotNull(adjustable, "adjustable"); if (! synchronizedAdjustables.contains(adjustable)) throw new IllegalStateException(tr("Adjustable {0} not registered yet. Cannot set participation in synchronized adjustment.", adjustable)); enabledMap.put(adjustable, isParticipating); observable.notifyObservers(); } /** * returns true if an adjustable is participating in synchronized scrolling * * @param adjustable the adjustable * @return true, if the adjustable is participating in synchronized scrolling, false otherwise * @throws IllegalStateException thrown, if adjustable is not registered for synchronized scrolling */ protected boolean isParticipatingInSynchronizedScrolling(Adjustable adjustable) throws IllegalStateException { if (! synchronizedAdjustables.contains(adjustable)) throw new IllegalStateException(tr("Adjustable {0} not registered yet.", adjustable)); return enabledMap.get(adjustable); } /** * wires a {@link JCheckBox} to the adjustment synchronizer, in such a way that: *
  • *
      state changes in the checkbox control whether the adjustable participates * in synchronized adjustment
    *
      state changes in this {@link AdjustmentSynchronizer} are reflected in the * {@link JCheckBox}
    *
  • * * * @param view the checkbox to control whether an adjustable participates in synchronized * adjustment * @param adjustable the adjustable * @exception IllegalArgumentException thrown, if view is null * @exception IllegalArgumentException thrown, if adjustable is null */ protected void adapt(final JCheckBox view, final Adjustable adjustable) throws IllegalStateException { CheckParameterUtil.ensureParameterNotNull(adjustable, "adjustable"); CheckParameterUtil.ensureParameterNotNull(view, "view"); if (! synchronizedAdjustables.contains(adjustable)) { participateInSynchronizedScrolling(adjustable); } // register an item lister with the check box // view.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { switch(e.getStateChange()) { case ItemEvent.SELECTED: if (!isParticipatingInSynchronizedScrolling(adjustable)) { setParticipatingInSynchronizedScrolling(adjustable, true); } break; case ItemEvent.DESELECTED: if (isParticipatingInSynchronizedScrolling(adjustable)) { setParticipatingInSynchronizedScrolling(adjustable, false); } break; } } }); observable.addObserver( new Observer() { public void update(Observable o, Object arg) { boolean sync = isParticipatingInSynchronizedScrolling(adjustable); if (view.isSelected() != sync) { view.setSelected(sync); } } } ); setParticipatingInSynchronizedScrolling(adjustable, true); view.setSelected(true); } }