// This file is part of the program FRYSK.//// Copyright 2007, Red Hat Inc.//// FRYSK is free software; you can redistribute it and/or modify it// under the terms of the GNU General Public License as published by// the Free Software Foundation; version 2 of the License.//// FRYSK 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// General Public License for more details.// // You should have received a copy of the GNU General Public License// along with FRYSK; if not, write to the Free Software Foundation,// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.// // In addition, as a special exception, Red Hat, Inc. gives You the// additional right to link the code of FRYSK with code not covered// under the GNU General Public License ("Non-GPL Code") and to// distribute linked combinations including the two, subject to the// limitations in this paragraph. Non-GPL Code permitted under this// exception must only link to the code of FRYSK through those well// defined interfaces identified in the file named EXCEPTION found in// the source code files (the "Approved Interfaces"). The files of// Non-GPL Code may instantiate templates or use macros or inline// functions from the Approved Interfaces without causing the// resulting work to be covered by the GNU General Public// License. Only Red Hat, Inc. may make changes or additions to the// list of Approved Interfaces. You must obey the GNU General Public// License in all respects for all of the FRYSK code and other code// used in conjunction with FRYSK except the Non-GPL Code covered by// this exception. If you modify this file, you may extend this// exception to your version of the file, but you are not obligated to// do so. If you do not wish to provide this exception without// modification, you must delete this exception statement from your// version and license this file solely under the GPL without// exception.package frysk.rt;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Observable;import java.util.Observer;import frysk.proc.Task;import frysk.stack.FrameIdentifier;/** * An UpdatingDisplayValue is nearly identical to a DisplayValue, except that * an UpdatingDisplayValue is provided with additional information that * enables it to automatically refresh itself whenever the task given to it * changes state. * * Objects can be notified of updates by using the addObserver method. * */public class UpdatingDisplayValue extends DisplayValue{ private SteppingEngine engine; private List observers; /** * Crate a new UpdatingDisplayValue * @param name The name of the variable to track * @param task The task from which to track the variable * @param fIdent The frame identifier corresponding to the scope from * which the variable should be read * @param eng The stepping engine to monitor for changes in execution * state */ public UpdatingDisplayValue (String name, Task task, FrameIdentifier fIdent, SteppingEngine eng) { super(name, task, fIdent); engine = eng; if(engine.getSteppingObserver() == null) engine.addProc(task.getProc()); engine.addObserver(new LockObserver()); observers = new LinkedList(); } public void refresh() { /* * If the task we're watching has no blockers, then that means it's running. * Which means that we've recieved an event for a task in the SteppingEngine * other than the one we're interested in. Do Nothing. */ if(myTask.getBlockers().length == 0) return; super.refresh(); // hear ye! hear ye! notifyObservers(); } /** * Adds an observer to listen for changes to this DisplayValue * @param obs The new observer to be notified */ public void addObserver(DisplayValueObserver obs) { observers.add(obs); } /** * Removes the given observer from the list of observers * @param obs The observer to remove * @return True if obs was found and removed, false otherwise */ public boolean removeObserver(DisplayValueObserver obs) { return observers.remove(obs); } /* * Called when we wish to notify the observers that there has been a * change in the watched value, should be called automatically at the * end of a refresh() */ protected void notifyObservers() { Iterator iter = observers.iterator(); while(iter.hasNext()) ((DisplayValueObserver) iter.next()).updateDisplayValueChanged(this); } private class LockObserver implements Observer { public void update (Observable observable, Object arg) { /* * arg will be null the first time this is fired: we don't need * any task-specific information from this observer, we have had * it all provided for us by the user */ if(arg != null) return; /* * arg was null, that means that we've recieved notification of a change * in the RunState of the task we're watching. trigger the update */ refresh(); } }}