// // Control.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad; import java.util.*; import java.rmi.*; /** Control is the abstract VisAD superclass for controls for DisplayRealTypes.<P> */ public abstract class Control extends Object implements Cloneable, java.io.Serializable { /** incremented by incTick */ private long NewTick; /** value of NewTick at last setTicks call */ private long OldTick; /** set by setTicks if OldTick < NewTick; cleared by resetTicks */ private boolean tickFlag; /** flag to indicate after setTicks and bfore resetTicks */ private boolean isSet = false; /** unique Display this Control is part of */ transient DisplayImpl display; transient DisplayRenderer displayRenderer; /** index of this in display.ControlVector */ private int Index; /** instance of this in display.ControlVector */ private int Instance; /** Vector of ControlListeners */ private transient Vector ListenerVector = new Vector(); /** * construct a Control for the given DisplayImpl * @param d - DisplayImpl this Control is associated with */ public Control(DisplayImpl d) { OldTick = Long.MIN_VALUE; NewTick = Long.MIN_VALUE + 1; tickFlag = false; display = d; Index = Instance = -1; if (display != null) displayRenderer = display.getDisplayRenderer(); } /** * @return DisplayRenderer assciated with this Control */ public DisplayRenderer getDisplayRenderer() { return displayRenderer; } /** * invoked every time values of this Control change * @param tick true to notify the Display for possible re-transform */ public void changeControl(boolean tick) throws VisADException, RemoteException { if (tick) incTick(); if (ListenerVector != null) { Vector clv = null; synchronized (ListenerVector) { clv = (Vector) ListenerVector.clone(); } Enumeration listeners = clv.elements(); while (listeners.hasMoreElements()) { ControlListener listener = (ControlListener) listeners.nextElement(); listener.controlChanged(new ControlEvent(this)); } } } /** * add a ControlListener * @param listener ControlListener to add */ public void addControlListener(ControlListener listener) { ListenerVector.addElement(listener); } /** * remove a ControlListener * @param listener ControlListener to remove */ public void removeControlListener(ControlListener listener) { if (listener != null) { ListenerVector.removeElement(listener); } } /** * end this control (called by ScalarMap.nullDisplay()) */ public void nullControl() { ListenerVector.removeAllElements(); } /** * increment long counter NewTick: NewTick > OldTick indicates * that there is event in this Control that the DisplayImpl * must process; * this method is invoked every time Control changes * @return incremented value of NewTick counter */ public long incTick() { NewTick += 1; if (NewTick == Long.MAX_VALUE) NewTick = Long.MIN_VALUE + 1; if (display != null) display.controlChanged(); // System.out.println(getClass().getName() + " set NewTick = " + NewTick); return NewTick; } /** * set tickFlag if NewTick > OldTick, and reset OldTick = NewTick * also invoke subSetTicks() to propagate to any sub-Controls */ public synchronized void setTicks() { if (isSet) return; // WLH 22 Aug 99 isSet = true; tickFlag = (OldTick < NewTick || (NewTick < 0 && 0 < OldTick)); // if (tickFlag) System.out.println(getClass().getName() + " set tickFlag = " + tickFlag); OldTick = NewTick; subSetTicks(); } /** * peek at future value of checkTicks() * @param r DataRenderer to check if changes to this Control * require re-transform * @param link DataDisplayLink involved in decision whether * changes to this Control require re-transform * @return true if checkTicks() will return true after next setTicks() */ public synchronized boolean peekTicks(DataRenderer r, DataDisplayLink link) { /* boolean flag = (OldTick < NewTick || (NewTick < 0 && 0 < OldTick)); System.out.println(getClass().getName() + " peek flag = " + flag + " trans = " + r.isTransformControl(this, link) + " sub = " + subPeekTicks(r, link)); */ return ((OldTick < NewTick || (NewTick < 0 && 0 < OldTick)) && r.isTransformControl(this, link)) || subPeekTicks(r, link); } /** * check if this Control changed and requires re-Transform * @param r DataRenderer to check if changes to this Control * require re-transform * @param link DataDisplayLink involved in decision whether * changes to this Control require re-transform * @return true if Control changed and requires re-Transform */ public synchronized boolean checkTicks(DataRenderer r, DataDisplayLink link) { /* boolean flag = (tickFlag && r.isTransformControl(this, link)) || subCheckTicks(r, link); if (tickFlag) { System.out.println(getClass().getName() + " check tickFlag = " + tickFlag + " trans = " + r.isTransformControl(this, link) + " sub = " + subCheckTicks(r, link)); } */ return (tickFlag && r.isTransformControl(this, link)) || subCheckTicks(r, link); } /** * reset tickFlag and propagate to sub-Controls */ public synchronized void resetTicks() { // if (tickFlag) System.out.println(getClass().getName() + " reset"); tickFlag = false; subResetTicks(); isSet = false; } /** * run setTicks on any sub-Controls; * this default for no sub-Controls */ public void subSetTicks() { } /** * run checkTicks on any sub-Controls * this default for no sub-Controls * @param r DataRenderer to check if changes to this Control * require re-transform * @param link DataDisplayLink involved in decision whether * changes to this Control require re-transform * @return 'logical or' of values from checkTicks on sub-Controls */ public boolean subCheckTicks(DataRenderer r, DataDisplayLink link) { return false; } /** * run peekTicks on any sub-Controls * this default for no sub-Controls * @param r DataRenderer to check if changes to this Control * require re-transform * @param link DataDisplayLink involved in decision whether * changes to this Control require re-transform * @return 'logical or' of values from peekTicks on sub-Controls */ public boolean subPeekTicks(DataRenderer r, DataDisplayLink link) { return false; } /** * run resetTicks on any sub-Controls * this default for no sub-Controls */ public void subResetTicks() { } /** * build String representation of current animation step * and pass it to DisplayRenderer.setAnimationString() * called by java3d.AnimationControlJ3D and java2d.AnimationControlJ2D * @param real - RealType mapped to Display.Animation * @param set - Set from AnimationSetControl * @param value - real value associated with current animation step * @param current - index of current animation step * @throws VisADException a VisAD error occurred */ public void animation_string(RealType real, Set set, double value, int current) throws VisADException { if (set != null) { Unit[] units = set.getSetUnits(); // WLH 31 Aug 2000 Vector tmap = display.getMapVector(); Unit overrideUnit = null; for (int i=0; i<tmap.size(); i++) { ScalarMap map = (ScalarMap) tmap.elementAt(i); Control c = map.getControl(); if (this.equals(c)) { overrideUnit = map.getOverrideUnit(); } } // units not part of Time string if (overrideUnit != null && units != null && !overrideUnit.equals(units[0]) && (!Unit.canConvert(units[0], CommonUnit.secondsSinceTheEpoch) || units[0].getAbsoluteUnit().equals(units[0]))) { value = overrideUnit.toThis(value, units[0]); units[0] = overrideUnit; } String s = real.getName() + " = " + new Real(real, value, units == null ? null : units[0]).toValueString(); String t = Integer.toString(current+1) + " of " + Integer.toString(set.getLength()); getDisplayRenderer().setAnimationString(new String[] {s, t}); } else { // null set getDisplayRenderer().setAnimationString(new String[] {null, null}); } } /** * set index of this Control in display.ControlVector * @param index new value to index to set */ void setIndex(int index) { Index = index; } /** * @return index of this Control in display.ControlVector */ int getIndex() { return Index; } /** * set 'instance number' (index + 1 ?) of this Control * in display.ControlVector * @param instance new value to 'instance number' to set */ void setInstanceNumber(int instance) { Instance = instance; } /** * @return 'instance number' (index + 1 ?) of this Control * in display.ControlVector */ public int getInstanceNumber() { return Instance; } /** * @return DisplayImpl associated with this Control */ public DisplayImpl getDisplay() { return display; } /** * @return String representation of this Control */ public abstract String getSaveString(); /** * reconstruct this Control using the specified save string * @param save - String representation for reconstruction * @throws VisADException if a VisAD error occurs * @throws RemoteException if an RMI error occurs */ public abstract void setSaveString(String save) throws VisADException, RemoteException; /** * copy the state of a remote control to this control * @param rmt remote Control whose state is copied * @throws VisADException if a VisAD error occurs */ public abstract void syncControl(Control rmt) throws VisADException; /** * @return a copy of this Control */ public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { return null; } } /** * Indicates whether or not this instance equals an Object * @param o an Object * @return true if and only if this instance is equal to o */ public boolean equals(Object o) { if (o == null || !getClass().isInstance(o)) { return false; } return (Instance == ((Control )o).Instance); } /** * @return a simple String representation of this Control */ public String toString() { String cn = getClass().getName(); int pt = cn.lastIndexOf('.'); final int ds = cn.lastIndexOf('$'); if (ds > pt) { pt = ds; } if (pt == -1) { pt = 0; } else { pt++; } return cn.substring(pt) + "@" + Index + "#" + Instance; } }