001package jmri.jmrit.symbolicprog;
002
003import java.awt.Color;
004import java.beans.PropertyChangeListener;
005import java.beans.PropertyChangeSupport;
006
007/**
008 * Represents a single CV or Variable value.  
009 * Defines common base class methods for CvValue and VariableValue classes
010 * <p>
011 * The ToRead parameter (boolean, unbound) is used to remember whether this
012 * object has been read during a "read all" operation. This allows removal of
013 * duplicate operations.
014 * <p>
015 * The ToWrite parameter (boolean, unbound) is used to remember whether this
016 * object has been written during a "write all" operation. This allows removal
017 * of duplicate operations.
018 * <p>
019 * The Available parameter (boolean, unbound) remembers whether the variable
020 * should be displayed, programmed, etc.
021 * <p>
022 * Variables and CVs track their states, as shown below.<br>
023 * <a href="doc-files/VariableStates.png"><img src="doc-files/VariableStates.png" alt="States for variables and their colors" height="33%" width="33%"></a>
024 * 
025 *
026 * @author Bob Jacobsen Copyright (C) 2001, 2005, 2026
027 */
028public abstract class AbstractValue {
029
030    PropertyChangeSupport prop = new PropertyChangeSupport(this);
031
032    /**
033     * Method to handle color changes for states.
034     *
035     * @param c the desired colour
036     */
037    abstract void setColor(Color c);
038
039    /**
040     * States, hence colors, of Variables and CVs.
041     *
042     * Note that these as written and read by name in LocoFiles in the roster.
043     * Do not change the name of these values without putting a migration scheme
044     * in place.
045     */
046    public enum ValueState {
047        /**
048         * Defines state when nothing is known about the real value.
049         */
050        UNKNOWN(Color.red.brighter(), "Unknown"),
051
052        /**
053         * Defines state where value has been edited, no longer same as in decoder
054         * or file.
055         */
056        EDITED(Color.orange, "Edited"),
057
058        /**
059         * Defines state where value has been read from (hence same as) decoder, but
060         * perhaps not same as in file.
061         */
062        READ(null, "Read"),
063
064        /**
065         * Defines state where value has been written to (hence same as) decoder,
066         * but perhaps not same as in file.
067         */
068        STORED(null, "Stored"),
069
070        /**
071         * Defines state where value was read from a config file, but might not be
072         * the same as the decoder. It is known to have been edited/read/written
073         * at some point.
074         */
075        FROMFILE(Color.yellow, "FromFile"),
076
077        /**
078         * Defines state where value was read from a config file, but might not be
079         * the same as the decoder. It's unknown whether the item has been edited/read/written
080         * at some point.
081         */
082        FROMFILEUNKNOWN(Color.yellow, "FromFileUnknown"),
083
084        /**
085         * Defines state where value was defined by the decoder definition default, 
086         * and has never been edited or read from or written to the decoder.
087         */
088        FROMDEFAULT(Color.yellow, "FromDefault"),  // ice blue 0xF0F8FF
089
090        /**
091         * Defines state where value was read from a config file, and is the same as
092         * the decoder.
093         */
094        SAME(null, "Same"),
095
096        /**
097         * Defines state where value was read from a config file, and is the not the
098         * same as the decoder.
099         */
100        DIFFERENT(Color.red.brighter(), "Different");
101
102
103        private final Color _color;
104        private final String _name;
105
106        private ValueState(Color color, String name) {
107            this._color = color;
108            this._name = name;
109        }
110
111        /**
112         * Gets the color associated with this state value.
113         * @return the color assigned to this state value or null if
114         *         to use default for the component
115         */
116        public Color getColor() {
117            return _color;
118        }
119
120        /**
121         * Gets the name associated with this state value.
122         * @return the name assigned to this state value
123         */
124        public String getName() {
125            return _name;
126        }
127    }
128
129    /**
130     * Mark whether this object needs to be read.
131     *
132     * @param state true if the object needs to be read, false otherwise
133     * @see AbstractValue
134     */
135    public void setToRead(boolean state) {
136        _toRead = state;
137    }
138
139    /**
140     * Ask whether this object needs to be read.
141     *
142     * @return true if the object needs to be read, false otherwise
143     * @see AbstractValue
144     */
145    public boolean isToRead() {
146        return _toRead;
147    }
148    private boolean _toRead = false;
149
150    /**
151     * Mark whether this object needs to be written.
152     *
153     * @param state true if the object needs to be written, false otherwise
154     * @see AbstractValue
155     */
156    public void setToWrite(boolean state) {
157        _toWrite = state;
158    }
159
160    /**
161     * Ask whether this object needs to be written.
162     *
163     * @return true if the object needs to be written, false otherwise
164     * @see AbstractValue
165     */
166    public boolean isToWrite() {
167        return _toWrite;
168    }
169    private boolean _toWrite = false;
170
171    /**
172     * Sets the availability status of the object.
173     *
174     * @param avail {@code true} if the object should be made available,
175     *              {@code false} if should be made unavailable
176     */
177    public void setAvailable(boolean avail) {
178        boolean oldval = this.available;
179        available = avail;
180        if (oldval != available) {
181            prop.firePropertyChange("Available", Boolean.valueOf(oldval), Boolean.valueOf(avail));
182        }
183    }
184
185    /**
186     * Gets the current availability status of the object.
187     * <p>
188     * Code can use this to determine whether to set object visibility (or other
189     * properties).
190     *
191     * @return {@code true} if the object should be available, {@code false} if
192     *         it should be unavailable
193     */
194    public boolean getAvailable() {
195        return available;
196    }
197    private boolean available = true;
198
199    /**
200     * @param p the listener to be added to the object
201     */
202    public void addPropertyChangeListener(PropertyChangeListener p) {
203        prop.addPropertyChangeListener(p);
204    }
205
206    /**
207     * @param p the listener to be removed from the object
208     */
209    public void removePropertyChangeListener(PropertyChangeListener p) {
210        prop.removePropertyChangeListener(p);
211    }
212}