Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Ruettimann2011-07-01 13:00:31 +0000
committerJonas Ruettimann2011-07-01 13:00:31 +0000
commit4e31671673053361a81c071fe744f38da4139e78 (patch)
treee7359b78fb323f69847d7e92b59f945788aebc6f
parent66d542ae506d202d4eb7df2c96a3610e066f66ef (diff)
downloadorg.eclipse.amp-4e31671673053361a81c071fe744f38da4139e78.tar.gz
org.eclipse.amp-4e31671673053361a81c071fe744f38da4139e78.tar.xz
org.eclipse.amp-4e31671673053361a81c071fe744f38da4139e78.zip
Bug 350813
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/model/Scape.java6839
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ControlEvent.java288
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/DefaultScapeListener.java15
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ScapeListener.java279
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViews.java68
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViewsEvent.java66
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/NonGraphicRunner.java91
-rw-r--r--org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/Runner.java3105
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/AbstractLifecycleListener.java242
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IEngine.java139
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IObservationProvider.java191
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifeCycleState.java4
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifecycleObservationAdapter.java95
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/.classpath1
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/plugin.xml102
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/EngineStateService.java173
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/HandlerManager.java73
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/ModelViewManager.java77
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/CloseHandler.java27
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ModelRunHandler.java66
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/PauseHandler.java36
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/RestartHandler.java27
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ResumeHandler.java30
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StartHandler.java28
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StepHandler.java28
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StopHandler.java28
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/EngineStateServiceTest.java369
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/CloseHandlerTest.java20
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ModelRunHandlerTest.java243
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/PauseHandlerTest.java20
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/RestartHandlerTest.java20
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ResumeHandlerTest.java20
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StartHandlerTest.java20
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StepHandlerTest.java20
-rw-r--r--org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StopHandlerTest.java20
-rw-r--r--org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ModelWrapperScapeListener.java256
-rw-r--r--org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ScapeWrapperModel.java377
-rw-r--r--org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ide/src/org/eclipse/amp/escape/ide/EclipseEscapeRunner.java7
39 files changed, 7168 insertions, 6345 deletions
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/Scape.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/Scape.java
index 6515a5ec..59942bd5 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/Scape.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/Scape.java
@@ -146,10 +146,9 @@ import org.ascape.util.vis.PlatformDrawFeature;
* scape execution. Normally you don't need to worry about controls as they are
* managed automatically by the framework.
*
- * Scapes can automatically
- * collect statistics on their members. (See StatCollectorCSA documentation for
- * a description of how stats are created.) Here is an example of how this might
- * be done:
+ * Scapes can automatically collect statistics on their members. (See
+ * StatCollectorCSA documentation for a description of how stats are created.)
+ * Here is an example of how this might be done:
*
* <pre>
* agents.addStatCollectors({new StatCollectorCSA() {
@@ -200,15 +199,15 @@ import org.ascape.util.vis.PlatformDrawFeature;
*
* Scapes are initialized and iterated hierarchically. The initialization and
* iteration process are rules, and their behavior is well defined. For example,
- * if you use the default list space for your root scape, scapes will be initialized and
- * iterated in the order in which they were added to the root. Of course, this
- * is an imporant consideration whenever there are dependencies between scapes.
- * On initialization, each scape first instantiates all of its members, and then
- * initializes them. After initialization, statistics are gathered, and views
- * are requested to update. Then, each rule is executed on its scape, statistics
- * are gathered, and views are requested to update. This continues until a
- * control event stops or pauses the model, or the iteration limit provided with
- * <code>setAutoStopAt</code> is reached.<BR>
+ * if you use the default list space for your root scape, scapes will be
+ * initialized and iterated in the order in which they were added to the root.
+ * Of course, this is an imporant consideration whenever there are dependencies
+ * between scapes. On initialization, each scape first instantiates all of its
+ * members, and then initializes them. After initialization, statistics are
+ * gathered, and views are requested to update. Then, each rule is executed on
+ * its scape, statistics are gathered, and views are requested to update. This
+ * continues until a control event stops or pauses the model, or the iteration
+ * limit provided with <code>setAutoStopAt</code> is reached.<BR>
* <BR>
* As stated, all scapes classes may act as a complete ascape model application.
* Using the construct methods, basic views and services are automatically added
@@ -303,3391 +302,3483 @@ import org.ascape.util.vis.PlatformDrawFeature;
*/
public class Scape extends CellOccupant implements SpaceContext, Collection, ControlListener, ScapeListener {
- /**
- * Increment this constant if you modify this class in a way that makes it
- * incompatible with the previous version, from a serialization standpoint.
- * Note that adding or removing serialized fields does not necessarily cause
- * incompatibility.
- */
- static final long serialVersionUID = 7686992038072599524L;
-
- /**
- * The current version of the Ascape framework as a whole. Returns "3.0" We
- * keep this in Scape since it is typically the invoked class.
- */
- public final static String version = "3.1";
-
- /**
- * Copyright and credits information for ascape w/ HTML style tags. Again,
- * we keep this in Scape since it is typically the invoked class.
- */
- public final static String copyrightAndCredits =
- "<B>Ascape version "
- + version
- + "</B><BR></BR>"
- + "Portions copyright 2000-2007, NuTech Solutions, Inc.<BR></BR>"
- +
- // "http://ascape.nutechsolutions.com<BR></BR>"
- // +
- "Portions copyright 1998-2000, The Brookings Institution<BR></BR>"
- + "JFreeChart Copyright (c) 2000, 2001, Simba Management Limited and others. (See licence-LGPL.txt)<BR></BR>"
- + "Icons (C)1998 Dean S. Jones<BR></BR>"
- + "Use subject to license agreement - see License.txt.<BR></BR>"
- + "Government Users -- Commercial Software subject to 48 C.F.R. ß12.212 or 48 C.F.R. ßß227.7202-1 through 227.7202-4.";
-
- /**
- * A rule causing the target scape and all its children scapes to be
- * populated if auto create is set to true.
- */
- public static final Rule CREATE_RULE = new PropogateScapeOnly("Create Scape") {
- /**
+ /**
+ * Increment this constant if you modify this class in a way that makes it
+ * incompatible with the previous version, from a serialization standpoint.
+ * Note that adding or removing serialized fields does not necessarily cause
+ * incompatibility.
+ */
+ static final long serialVersionUID = 7686992038072599524L;
+
+ /**
+ * The current version of the Ascape framework as a whole. Returns "3.0" We
+ * keep this in Scape since it is typically the invoked class.
+ */
+ public final static String version = "3.1";
+
+ /**
+ * Copyright and credits information for ascape w/ HTML style tags. Again, we
+ * keep this in Scape since it is typically the invoked class.
+ */
+ public final static String copyrightAndCredits = "<B>Ascape version " + version + "</B><BR></BR>" + "Portions copyright 2000-2007, NuTech Solutions, Inc.<BR></BR>" +
+ // "http://ascape.nutechsolutions.com<BR></BR>"
+ // +
+ "Portions copyright 1998-2000, The Brookings Institution<BR></BR>" + "JFreeChart Copyright (c) 2000, 2001, Simba Management Limited and others. (See licence-LGPL.txt)<BR></BR>" + "Icons (C)1998 Dean S. Jones<BR></BR>" + "Use subject to license agreement - see License.txt.<BR></BR>" + "Government Users -- Commercial Software subject to 48 C.F.R. ß12.212 or 48 C.F.R. ßß227.7202-1 through 227.7202-4.";
+
+ /**
+ * A rule causing the target scape and all its children scapes to be populated
+ * if auto create is set to true.
+ */
+ public static final Rule CREATE_RULE = new PropogateScapeOnly("Create Scape") {
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- /**
- * populates the scape and all its children.
- *
- * @param agent the playing agent
- */
- public void execute(Agent agent) {
- if (((Scape) agent).isAutoCreate()) {
- ((Scape) agent).createScape();
- }
- /*
- * if (((Scape) agent).getCustomizer() != null) { ((Scape)
- * agent).getCustomizer().build(); }
- */
- super.execute(agent);
- }
-
- public boolean isIterateAll() {
- return true;
- }
- };
-
- /**
- * A rule causing viwews to be created for scape and all subscapes. Creates
- * views for the resulting scapes.
- */
- public static final Rule CREATE_VIEW_RULE = new PropogateScapeOnly("Create Views") {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Creates views for all of the scapes.
- *
- * @param agent the playing agent
- */
- public void execute(Agent agent) {
- ((Scape) agent).createViews();
- super.execute(agent);
- }
-
- public boolean isIterateAll() {
- return true;
- }
- };
-
- /**
- * A rule causing graphic views to be created for scape and all subscapes.
- */
- public static final Rule CREATE_GRAPHIC_VIEW_RULE = new PropogateScapeOnly("Create Graphic Views") {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Creates views for all of the scapes.
- *
- * @param agent the playing agent
- */
- public void execute(Agent agent) {
- ((Scape) agent).createGraphicViews();
- super.execute(agent);
- }
-
- public boolean isIterateAll() {
- return true;
- }
- };
-
- /**
- * A rule causing the target scape to be populated.
- */
- public static final Rule CREATE_SCAPE_RULE = new Rule("Create Scape") {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * populates the scape and all its children.
- *
- * @param agent the playing agent
- */
- public void execute(Agent agent) {
- ((Scape) agent).createScape();
- }
-
- public boolean isIterateAll() {
- return true;
- }
- };
-
- /**
- * A rule causing the targets initial rules to be executed on its members.
- */
- public static final Rule INITIAL_RULES_RULE = new PropogateScapeOnly("Initial Rules") {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Initializes the scape and all its children.
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * populates the scape and all its children.
+ *
+ * @param agent
+ * the playing agent
+ */
+ public void execute(Agent agent) {
+ if (((Scape) agent).isAutoCreate()) {
+ ((Scape) agent).createScape();
+ }
+ /*
+ * if (((Scape) agent).getCustomizer() != null) { ((Scape)
+ * agent).getCustomizer().build(); }
+ */
+ super.execute(agent);
+ }
+
+ public boolean isIterateAll() {
+ return true;
+ }
+ };
+
+ /**
+ * A rule causing viwews to be created for scape and all subscapes. Creates
+ * views for the resulting scapes.
+ */
+ public static final Rule CREATE_VIEW_RULE = new PropogateScapeOnly("Create Views") {
+ /**
*
- * @param agent the playing agent
- * @see Scape#getInitialRules()
*/
- public void execute(Agent agent) {
- super.execute(agent);
- int iterations = 0;
- int style = 0;
- if (((Scape) agent).getSpace() instanceof Discrete) {
- iterations = ((Scape) agent).getAgentsPerIteration();
- style = ((Scape) agent).getExecutionStyle();
- ((Scape) agent).setExecutionStyle(Scape.COMPLETE_TOUR);
- ((Scape) agent).setAgentsPerIteration(Scape.ALL_AGENTS);
- }
- ((Scape) agent).executeOnMembers(((Scape) agent).getInitialRules());
- if (((Scape) agent).getSpace() instanceof Discrete) {
- ((Scape) agent).setAgentsPerIteration(iterations);
- ((Scape) agent).setExecutionStyle(style);
- }
- }
-
- public boolean isIterateAll() {
- return true;
- }
- };
-
- /**
- * A rule causing all children and members that are scapes to iterate.
- * Executes all rules that have been added to each scape, increments the
- * scape counter, and collectes and stores statistics for any scapes with a
- * statistics collection rule.
- */
- public final static Rule EXECUTE_RULES_RULE = new PropogateScapeOnly("Iterate Scape") {
- /**
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates views for all of the scapes.
+ *
+ * @param agent
+ * the playing agent
+ */
+ public void execute(Agent agent) {
+ ((Scape) agent).createViews();
+ super.execute(agent);
+ }
+
+ public boolean isIterateAll() {
+ return true;
+ }
+ };
+
+ /**
+ * A rule causing graphic views to be created for scape and all subscapes.
+ */
+ public static final Rule CREATE_GRAPHIC_VIEW_RULE = new PropogateScapeOnly("Create Graphic Views") {
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- /**
- * Iterate over every member and child.
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates views for all of the scapes.
+ *
+ * @param agent
+ * the playing agent
+ */
+ public void execute(Agent agent) {
+ ((Scape) agent).createGraphicViews();
+ super.execute(agent);
+ }
+
+ public boolean isIterateAll() {
+ return true;
+ }
+ };
+
+ /**
+ * A rule causing the target scape to be populated.
+ */
+ public static final Rule CREATE_SCAPE_RULE = new Rule("Create Scape") {
+ /**
*
- * @param agent the target agent
*/
- public void execute(Agent agent) {
- ((Scape) agent).executeOnMembers();
- super.execute(agent);
- }
- };
-
- /**
- * A rule causing all children and members that are scapes to iterate.
- * Executes all rules that have been added to each scape, increments the
- * scape counter, and collectes and stores statistics for any scapes with a
- * statistics collection rule.
- */
- public final static Rule CLEAR_STATS_RULE = new PropogateScapeOnly("Iterate Scape") {
- /**
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * populates the scape and all its children.
+ *
+ * @param agent
+ * the playing agent
+ */
+ public void execute(Agent agent) {
+ ((Scape) agent).createScape();
+ }
+
+ public boolean isIterateAll() {
+ return true;
+ }
+ };
+
+ /**
+ * A rule causing the targets initial rules to be executed on its members.
+ */
+ public static final Rule INITIAL_RULES_RULE = new PropogateScapeOnly("Initial Rules") {
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- /**
- * Iterate over every member and child.
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Initializes the scape and all its children.
+ *
+ * @param agent
+ * the playing agent
+ * @see Scape#getInitialRules()
+ */
+ public void execute(Agent agent) {
+ super.execute(agent);
+ int iterations = 0;
+ int style = 0;
+ if (((Scape) agent).getSpace() instanceof Discrete) {
+ iterations = ((Scape) agent).getAgentsPerIteration();
+ style = ((Scape) agent).getExecutionStyle();
+ ((Scape) agent).setExecutionStyle(Scape.COMPLETE_TOUR);
+ ((Scape) agent).setAgentsPerIteration(Scape.ALL_AGENTS);
+ }
+ ((Scape) agent).executeOnMembers(((Scape) agent).getInitialRules());
+ if (((Scape) agent).getSpace() instanceof Discrete) {
+ ((Scape) agent).setAgentsPerIteration(iterations);
+ ((Scape) agent).setExecutionStyle(style);
+ }
+ }
+
+ public boolean isIterateAll() {
+ return true;
+ }
+ };
+
+ /**
+ * A rule causing all children and members that are scapes to iterate.
+ * Executes all rules that have been added to each scape, increments the scape
+ * counter, and collectes and stores statistics for any scapes with a
+ * statistics collection rule.
+ */
+ public final static Rule EXECUTE_RULES_RULE = new PropogateScapeOnly("Iterate Scape") {
+ /**
*
- * @param agent the target agent
*/
- public void execute(Agent agent) {
- CollectStats collectStats = ((Scape) agent).getCollectStats();
- if (collectStats != null) {
- collectStats.clear();
- }
- super.execute(agent);
- }
- };
-
- /**
- * A rule causing all children and members that are scapes to iterate.
- * Executes all rules that have been added to each scape, increments the
- * scape counter, and collectes and stores statistics for any scapes with a
- * statistics collection rule.
- */
- public final static Rule COLLECT_STATS_RULE = new PropogateScapeOnly("Iterate Scape") {
- /**
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Iterate over every member and child.
+ *
+ * @param agent
+ * the target agent
+ */
+ public void execute(Agent agent) {
+ ((Scape) agent).executeOnMembers();
+ super.execute(agent);
+ }
+ };
+
+ /**
+ * A rule causing all children and members that are scapes to iterate.
+ * Executes all rules that have been added to each scape, increments the scape
+ * counter, and collectes and stores statistics for any scapes with a
+ * statistics collection rule.
+ */
+ public final static Rule CLEAR_STATS_RULE = new PropogateScapeOnly("Iterate Scape") {
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- /**
- * Iterate over every member and child.
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Iterate over every member and child.
+ *
+ * @param agent
+ * the target agent
+ */
+ public void execute(Agent agent) {
+ CollectStats collectStats = ((Scape) agent).getCollectStats();
+ if (collectStats != null) {
+ collectStats.clear();
+ }
+ super.execute(agent);
+ }
+ };
+
+ /**
+ * A rule causing all children and members that are scapes to iterate.
+ * Executes all rules that have been added to each scape, increments the scape
+ * counter, and collectes and stores statistics for any scapes with a
+ * statistics collection rule.
+ */
+ public final static Rule COLLECT_STATS_RULE = new PropogateScapeOnly("Iterate Scape") {
+ /**
*
- * @param agent the target agent
*/
- public void execute(Agent agent) {
- CollectStats collectStats = ((Scape) agent).getCollectStats();
- // Special case for value collection rule
- if (collectStats != null) {
- /*
- * int iterations = ScapeDiscrete.ALL_AGENTS; if (agent
- * instanceof ScapeDiscrete) { iterations = ((ScapeDiscrete)
- * agent).getAgentsPerIteration(); ((ScapeDiscrete)
- * agent).setAgentsPerIteration(ScapeDiscrete.ALL_AGENTS); }
- */
- collectStats.setPhase(1);
- ((Scape) agent).executeOnMembers(collectStats);
- collectStats.setPhase(2);
- ((Scape) agent).executeOnMembers(collectStats);
- /*
- * if (agent instanceof ScapeDiscrete) { ((ScapeDiscrete)
- * agent).setAgentsPerIteration(iterations); }
- */
- }
- super.execute(agent);
- if (collectStats != null) {
- collectStats.calculateValues();
- }
- if (((Scape) agent).isRoot() && ((Scape) agent).getRunner().getData() != null) {
- ((Scape) agent).getRunner().getData().update();
- // System.gc();
- }
- }
- };
-
- /**
- * The symbol to execute rules against all agents in each iteration.
- */
- public final static int ALL_AGENTS = -1;
-
- /**
- * Symbol for by agent execution order.
- */
- public final static int AGENT_ORDER = -2;
-
- /**
- * Symbol for by rule execution order.
- */
- public final static int RULE_ORDER = -1;
-
- /**
- * Symbol for complete tour excution style.
- */
- public final static int COMPLETE_TOUR = 1;
-
- /**
- * Symbol for repeated random draw execution style.
- */
- public final static int REPEATED_DRAW = 2;
-
- /**
- * Manages time, model-wide views and other features that are shared between
- * scapes. There is one an only one for each model instance.
- */
- private Runner runner;
-
- private Space space;
-
- /**
- * An agent which which may be cloned to produce members of this collection.
- * By default, all scapes which have a known number of members are
- * initialized with clones of this agent.
- */
- protected Agent prototypeAgent;
-
- /**
- * The rules that this scape will execute on its memebers.
- */
- private VectorSelection rules = new VectorSelection(new Vector());
-
- /**
- * The rules that this scape will execute on its members upon initializtion.
- */
- protected VectorSelection initialRules = new VectorSelection(new Vector());
-
- /**
- * The observers of this scape. All listeners are notified when the scape is
- * updated and given a chance to update themselves.
- */
- private ArrayList scapeListeners = new ArrayList();
-
- /**
- * The number of agents to execute each rule across for each iteration.
- */
- protected int agentsPerIteration = ALL_AGENTS;
-
- /**
- * Order in which rules should be executed.
- */
- private int executionOrder = AGENT_ORDER;
-
- /**
- * 'Stlye' of rule execution.
- */
- private int executionStyle = COMPLETE_TOUR;
-
- /**
- * Should members of the scape be iterated against?
- */
- private boolean membersActive = true;
-
- /**
- * Should members of the scape be automatically created at startup?
- */
- private boolean autoCreate = true;
-
- /**
- * Should the scape be populated on creation?
- */
- private boolean populateOnCreate = true;
-
- /**
- * Should cells indicate that they need to be updated manually (imroving
- * performance significantly) or should all cells be updated every
- * iteration.
- */
- private boolean cellsRequestUpdates = false;
-
- /**
- * The value collection rule for this scape. Null if no values should be
- * collected.
- */
- private CollectStats collectStats = null;
-
- /**
- * A view of the scape that delegates back to the scape, often null.
- * Automatically created for root when standard model is used.
- */
- private ScapeListener selfView;
-
- /**
- * A vector of features available to draw memebers of this scape.
- */
- private Vector drawFeatures = new Vector();
-
- /**
- * Are all the listeners and members (which may have listeners) of this
- * scape current? (If so, we can continue updating, otherwise, we must wait.
- */
- private boolean listenersAndMembersCurrent = false;
-
- /**
- * Determines how many time steps pass between updating displayed charts and
- * graphs. Higher numbers result in faster performance but less frequent
- * updates. This setting does not affect model results.
- */
- private int iterationsPerRedraw = 1;
-
- /**
- * Count of the number of listeners that have been updated. Used to
- * determine when all listeners have been updated.
- */
- private int updatedListeners = 0;
-
- /**
- * Count of the number of members that have been updated. Used to determine
- * when all members have been updated.
- */
- private int updatedMembers = 0;
-
- private boolean serializable = true;
-
- /**
- * Constructs a scape with default list topology.
- */
- public Scape() {
- this(new ListSpace());
- }
-
- /**
- * Constructs a scape.
- *
- * @param space the topology for this scape
- */
- public Scape(CollectionSpace space) {
- this(space, null, null);
- }
-
- /**
- * Constructs a scape of provided geometry, to be populated with clones of
- * provided agent.
- *
- * @param name a descriptive name for the scape
- * @param prototypeAgent the agent whose clones will be used to populate
- * this scape
- */
- public Scape(String name, Agent prototypeAgent) {
- this(null, name, prototypeAgent);
- }
-
- /**
- * Constructs a scape of provided geometry, to be populated with clones of
- * provided agent.
- *
- * @param name a descriptive name for the scape
- * @param prototypeAgent the agent whose clones will be used to populate
- * this scape
- * @param space the topology for this scape
- */
- public Scape(CollectionSpace space, String name, Agent prototypeAgent) {
- super();
- setSpace(space);
- setName(name);
- setPrototypeAgent(prototypeAgent);
- scapeListeners = new ArrayList();
- listenersAndMembersCurrent = true;
- }
-
- /**
- * Returns the size, or number of agents, of this Scape.
- */
- public int getSize() {
- return space.getSize();
- // return vector.size();
- }
-
- /**
- * Sets the prototype agent, the agent that, in default implementations,
- * will be cloned to populate this scape. It is an error to call while the
- * scape is running.
- *
- * @param prototypeAgent the agent whose clones will populate this scape
- */
- public void setPrototypeAgent(Agent prototypeAgent) {
- this.prototypeAgent = prototypeAgent;
- if (prototypeAgent != null && prototypeAgent.getScape() == null) {
- prototypeAgent.setScape(this);
- prototypeAgent.scapeCreated();
- }
- setInitialized(false);
- }
-
- /**
- * Returns the agent that is cloned to populate this scape.
- */
- public Agent getPrototypeAgent() {
- return prototypeAgent;
- }
-
- /**
- * Returns the number of agents to iterate through each iteration cycle.
- * *@param returns the number of iterations per cycle
- */
- public int getAgentsPerIteration() {
- return agentsPerIteration;
- }
-
- /**
- * Sets the number of agents to iterate through each iteration cycle. By
- * default, set to iterate through all agents. *@param agentsPerIteration
- * the number of agents to iterate against per cycle, ALL_AGENTS for all
- * agents
- */
- public void setAgentsPerIteration(int agentsPerIteration) {
- this.agentsPerIteration = agentsPerIteration;
- }
-
- /**
- * Returns the number of iterations to perform before updating views.
- */
- public int getIterationsPerRedraw() {
- return iterationsPerRedraw;
- }
-
- /**
- * Sets the number of iterations to perform before updating views, and
- * propagates this setting to all scapes and views in the model.
- */
- public void setIterationsPerRedraw(int iterationsPerRedraw) {
- setIterationsPerRedraw(iterationsPerRedraw, true);
- }
-
- /**
- * Sets the number of iterations to perform before updating views, and
- * optionally propagates this setting to all scapes and views in the model.
- */
- public void setIterationsPerRedraw(int iterationsPerRedraw, boolean propagate) {
- this.iterationsPerRedraw = iterationsPerRedraw;
- if (propagate) {
- executeOnRoot(new NotifyViews(ScapeEvent.REQUEST_CHANGE_ITERATIONS_PER_REDRAW) {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- public void execute(Agent agent) {
- ((Scape) agent).setIterationsPerRedraw(agent.getRoot().getIterationsPerRedraw(), false);
- super.execute(agent);
- }
- });
- }
- }
-
- /**
- * Returns the execution order that has been set for this scape.
- */
- public int getExecutionOrder() {
- return executionOrder;
- }
-
- /**
- * Sets the order of rule execution for this scape. If 'rule order', each
- * rule is executed on every agent in turn. If 'agent order', every rule is
- * executed on each agent in turn. Execution order can be profoundly
- * significant to a model's dynamics. For 'synchrounous' style rules that
- * subclass ExecuteAndUpdate, 'by rule' execution is the only order that
- * makes sense.
- *
- * @param symbol RULE_ORDER for by rule execution, AGENT_ORDER for by agent
- * execution
- */
- public void setExecutionOrder(int symbol) {
- this.executionOrder = symbol;
- }
-
- /**
- * Returns the execution style that has been set for this scape.
- */
- public int getExecutionStyle() {
- return executionStyle;
- }
-
- /**
- * Sets the style that rules will be executed upon this scape. If complete
- * tour, every agent is visited once and only once (assuming agents per
- * iteration is set to 'all agents'.) If repeated draw, a random agent is
- * picked n times for execution. (Actually, if execution order is by agent,
- * each rule is then executed upon the picked agent, so that there are n
- * total draws. But if execution order is by rule, then for each rule, a
- * random agent is picked, which means that there are actually (rules X n)
- * draws. In practice, this combination does not seem to make much sense in
- * any case.) A complete tour style of execution seems generally more
- * plausible, but a repeated draw approach can produce different and
- * interesting results.
- *
- * @param symbol one of COMPLETE_TOUR or REPEATED_DRAW
- */
- public void setExecutionStyle(int symbol) {
- this.executionStyle = symbol;
- }
-
- /**
- * Returns the extent of the scape. The extent can be thought of as the most
- * extreme point in the scape. For discrete scape's this will simply be the
- * furthest cell, so that for a 20x20 grid, the extent would be {20, 20}.
- * For continuous spaces it will be the maximum boundary of the space. For
- * lists, it will be the size of lists. Therefore, this method should net be
- * confused with the scape's "size". Note that scape graphs will not have
- * useful extents, but all other scapes do.
- */
- public Coordinate getExtent() {
- return space.getExtent();
- }
-
- /**
- * Sets the size of the scape. Note that scape graphs will not have useful
- * extents, but all other scapes do. It is an error to set extent while a
- * scape is running.
- *
- * @param extent a coordinate at the maximum extent
- */
- public void setExtent(Coordinate extent) {
- if (getRunner() != null && getRunner().isRunning()) {
- throw new RuntimeException("Tried to modfiy extent while scape was running");
- }
- space.setExtent(extent);
- }
-
- /**
- * Sets the size of the scape. Note that scape graphs will not have useful
- * extents, but all other scapes do. It is an error to set extent while a
- * scape is running.
- *
- * @throws RuntimeException if the scape is currently running
- * @param xval coordinate 1 of the extent
- */
- public void setExtent(int xval) {
- if (runner != null && runner.isRunning()) {
- throw new RuntimeException("Tried to modfiy extent while scape was running");
- }
- if (getSpace().getGeometry().getDimensionCount() != 1) {
- throw new RuntimeException("Tried to set extent as 1-dimension for a scape that isn't 1-dimensional.");
- }
- ((CollectionSpace) getSpace()).setExtent(xval);
- }
-
- /**
- * Sets the size of the scape. Note that scape graphs will not have useful
- * extents, but all other scapes do. It is an error to set extent while a
- * scape is running.
- *
- * @param xval coordinate 1 of the extent
- * @param yval coordinate 2 of the extent
- * @throws RuntimeException if the scape is currently running
- * @throws UnsupportedOperationException if the underlying space isn't
- * appropriate
- */
- public void setExtent(int xval, int yval) {
- if (runner != null && runner.isRunning()) {
- throw new RuntimeException("Tried to modfiy extent while scape was running");
- }
- try {
- ((Array2DBase) getSpace()).setExtent(xval, yval);
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException("Can't set extent as x, y; underlying scape doesn't support it.");
- }
- }
-
- /**
- * Returns the name of this scape, the model name if this is root and there
- * is no name set.
- */
- public String getName() {
- if (name != null) {
- return name;
- } else {
- return getClass().getName();
- }
- }
-
- private void loadDescriptions() {
- if (getRunner().getDescription() == null || getRunner().getHTMLDescription() == null) {
- String fileName = "About" + Utility.getClassNameOnly(this.getClass()) + ".html";
- URL aboutFile = this.getClass().getResource(fileName);
- if (aboutFile != null) {
- getRunner().setDescription("");
- try {
- BufferedInputStream is = (BufferedInputStream) aboutFile.getContent();
- BufferedReader ir = new BufferedReader(new InputStreamReader(is));
- String nextLine = ir.readLine();
- // Clean out html tags
- StringBuffer htmlFragBuffer = new StringBuffer();
- while (nextLine != null) {
- htmlFragBuffer.append(nextLine);
- nextLine = ir.readLine();
- }
- StringBuffer plainTextBuffer = new StringBuffer();
- // Neccessary to support 1.3
- String htmlString = htmlFragBuffer.toString();
- boolean done = false;
- int pos = 0;
- while (!done) {
- int anglePos = htmlString.indexOf("<", pos);
- if (anglePos >= 0) {
- plainTextBuffer.append(htmlFragBuffer.substring(pos, anglePos));
- if (htmlFragBuffer.substring(anglePos, anglePos + 4).equalsIgnoreCase("<BR>")) {
- plainTextBuffer.append("\n");
- }
- pos = htmlString.indexOf(">", anglePos) + 1;
- } else {
- plainTextBuffer.append(htmlFragBuffer.substring(pos, htmlFragBuffer.length()));
- done = true;
- }
- }
- setHTMLDescription(htmlFragBuffer.toString());
- setDescription(plainTextBuffer.toString());
- } catch (java.io.IOException e) {
- // Probably file has not been defined; in any case, just use
- // toString value..
- getEnvironment().getConsole().println("Non-critical exception: couldn't read \"About\" file: " + e);
- getRunner().setDescription(toString());
- }
- } else {
- // No about file defined
- getRunner().setDescription(toString());
- }
- }
- }
-
- /**
- * Returns a long (paragraph length suggested) description of the scape. The
- * root scape should describe the model as a whole; subscapes should
- * describe themselves. Plantext. If no description is provided, return the
- * standar toString() description. This description is automatically loaded
- * from a file called "About[ModelClassName].html" located in the the same
- * directory as the .class file for the model, if such a file exists. To use
- * this feature simply create such a file and place it in the appropriate
- * directory. You can include any normal html style tags in this file, they
- * will be stripped from the non-html description.
- */
- public String getDescription() {
- try {
- loadDescriptions();
- return getRunner().getDescription();
- } catch (ClassCastException cce) {
- return "";
- }
- }
-
- /**
- * Returns a long (paragraph length suggested) description of the scape. The
- * root scape should describe the model as a whole; subscapes should
- * describe themselves. If no description is provided, return the standar
- * toString() description.
- */
- public void setDescription(String description) {
- getRunner().setDescription(description);
- }
-
- /**
- * Returns a long (paragraph length suggested) description of the scape. The
- * root scape should describe the model as a whole; subscapes should
- * describe themselves. Includes html tags as appropriate. This description
- * is automatically loaded from a file called "About[ModelClassName].html"
- * located in the the same directory as the .class file for the model, if
- * such a file exists. To use this feature simply create such a file and
- * place it in the appropriate directory. You can include any normal html
- * style tags in this file, they will be stripped from the non-html
- * description. If no description is provided, return the standar toString()
- * description.
- */
- public String getHTMLDescription() {
- loadDescriptions();
- return getRunner().getHTMLDescription();
- }
-
- /**
- * Returns a long (paragraph length suggested) description of the scape. The
- * root scape should describe the model as a whole; subscapes should
- * describe themselves. Should include html tags as appropriate. If no
- * description is provided, return the standar toString() description.
- */
- public void setHTMLDescription(String description) {
- getRunner().setHTMLDescription(description);
- }
-
- /**
- * Returns the root of this scape, which may be this scape.
- */
- public final Scape getRoot() {
- if (scape == null) {
- return this;
- } else {
- return scape.getRoot();
- }
- }
-
- /**
- * Is this scape the root within its entire simulation context? That is,
- * does this root not have any parent scapes?
- */
- public boolean isRoot() {
- return scape == null;
- }
-
- /**
- * Has a view update been requested for this cell?
- */
- public boolean isUpdateNeeded() {
- return isUpdateNeeded(getIterationsPerRedraw());
- }
-
- /**
- * Contructs the basic scape structure. Instantiates the agents, but does
- * not populate them. It is not neccesary to set extent before initializing
- * a collection, unless you want to have a populated vecotr to begin with.
- */
- public void construct() {
- space.construct();
- if (getSpace() instanceof Discrete && getPrototypeAgent() == null) {
- setPrototypeAgent(new Cell());
- }
- }
-
- /**
- * Populates the scape with clones of the prototype agent. Prototype agent
- * should be set before calling this method.
- */
- public void populate() {
- space.populate();
- }
-
- /**
- * Create this scape; contruct it, populate it, add rules, create statistic
- * collectors, etc. Called automatically at model construction, unless
- * isAutoCreate is set to false. By default, automatically populates all
- * members with clones of the prototype agent. Of course, this behavior can
- * be overridden or embellished. To turn off the populate behavior, set
- * populate on create to false.
- *
- * @see #setPopulateOnCreate
- */
- public void createScape() {
- // We use Scape as a prototype simply because Scape is abstract and so
- // can't be
- // instantiated. Any scape will do, since we won't be cloning it to
- // populate.
- if (isRoot()) {
- if (getPrototypeAgent() == null) {
- setPrototypeAgent(new Scape());
- }
- if (getRunner() == null) {
- new NonGraphicRunner().setRootScape(this);
- }
- }
- construct();
- if (isPopulateOnCreate()) {
- populate();
- }
- }
-
- /**
- * Initializes the state of the scape. This is the appropriate place to put
- * any initialization that is dependent on the state of other ascape
- * objects. If autoCreate is true, calls createScape() on the scape. Note
- * that for root scapes, autoCreate is always false. Objects are initialized
- * in the order they are added to parent scapes.
- */
- public void initialize() {
- if (isRoot()) {
- setAutoCreate(false);
- }
- if (isAutoCreate()) {
- createScape();
- }
- super.initialize();
- getSpace().initialize();
- if (!(getSpace() instanceof Continuous) && getPrototypeAgent() != null
- && getPrototypeAgent().getScape() == this && !getSpace().isMutable()) {
- executeOnMembers(Cell.CALCULATE_NEIGHBORS_RULE);
- }
- }
-
- /**
- * Returns current count of iterations.
- */
- public final int getIteration() {
- return getRunner().getIteration();
- }
-
- /**
- * Returns the current period, which is just the iteration plus the period
- * begin.
- */
- public final int getPeriod() {
- return getRunner().getPeriod();
- }
-
- /**
- * Returns the name that periods are referred to by.
- */
- public String getPeriodName() {
- return getRunner().getPeriodName();
- }
-
- /**
- * Returns a string description of the current period, i.e. "Iteration 1",
- * "Year 1900", "StarDate 3465.29."
- */
- public String getPeriodDescription() {
- return getPeriodName() + " " + Integer.toString(getPeriod());
- }
-
- /**
- * Sets the name that periods are referred to by.
- */
- public void setPeriodName(String name) {
- getRunner().setPeriodName(name);
- }
-
- /**
- * Adds a rule to this scape, automatically selecting it.
- */
- public synchronized void addRule(Rule rule) {
- addRule(rule, true);
- }
-
- /**
- * Adds a rule to this scape. Allows setting whether rule be should be
- * selected (run) automatically? If the selection is not changed, rules are
- * executed in the order they are added.
- *
- * @param rule the rule to add
- * @param select if rule should be run false if rule should just be made
- * available to be run
- */
- public synchronized void addRule(Rule rule, boolean select) {
- if (rule instanceof ExecuteThenUpdate && getExecutionOrder() != RULE_ORDER) {
- // bug mtp: need to add similar check when setting rule order.
- throw new RuntimeException(
- "Tried to add execute and update rule to AGENT_ORDER Scape. Set Scape to RULE_ORDER execution first.");
- }
- if (rule.getScape() == null) {
- rule.setScape(this);
- }
- rules.addElement(rule, select);
- }
-
- /**
- * Returns all rules that this scape might execute.
- */
- public VectorSelection getRules() {
- return rules;
- }
-
- /**
- * Adds a rule to be executed once following initialization. Rule is
- * automatically selected for running.
- *
- * @param rule to be executed at simulation start
- */
- public synchronized void addInitialRule(Rule rule) {
- addInitialRule(rule, true);
- }
-
- /**
- * Adds a rule to be executed once following initialization. If the
- * selection is not chagned, rules are executed in the order they are added.
- *
- * @param rule to be executed at simulation start
- * @param select if rule should be run false if rule should just be made
- * available to be run
- */
- public synchronized void addInitialRule(Rule rule, boolean select) {
- if (rule.getScape() == null) {
- rule.setScape(this);
- }
- initialRules.addElement(rule, select);
- }
-
- /**
- * Returns all the rules executed following scape initialization.
- */
- public VectorSelection getInitialRules() {
- return initialRules;
- }
-
- public void setInitialRules(VectorSelection initialRules) {
- this.initialRules = initialRules;
- }
-
- /**
- * Adds a view to this scape. Takes care of basic housekeeping, including
- * registering view as listener, and creating window for view to be
- * displayed within.
- *
- * @param view ComponentView to display in window
- */
- public synchronized void addView(ScapeListener view) {
- this.addView(view, true);
- }
-
- /**
- * Adds a view to this scape. Takes care of basic housekeeping, including
- * registering view as listener, and creating window for view to be
- * displayed within. This version of the method allow the adding of a view
- * without regard to the GUI setting. This method might be useful for
- * instace when temporaily instrumenting a non-gui run with diagnostics.
- * Normally addScapeListener should be used.
- *
- * @param view ComponentView to display in window
- * @param createFrame should the view be placed within a new window frame?
- * @param forceGUI add a GUI view witout regard to the display GUI setting
- */
- public synchronized void addView(final ScapeListener view, boolean createFrame, boolean forceGUI) {
- if (forceGUI || Runner.isDisplayGraphics() || !view.isGraphic() || Runner.isServeGraphics()) {
- try {
- this.addScapeListener(view);
- // if (view instanceof Component) {
- // // try {
- // SwingUtilities.invokeLater(new Runnable() {
- // public void run() {
- // view.scapeNotification(new ScapeEvent(Scape.this,
- // ScapeEvent.REPORT_ADDED));
- // }
- // });
- // // } catch (InterruptedException e) {
- // // e.printStackTrace();
- // // } catch (InvocationTargetException e) {
- // // e.printStackTrace();
- // // }
- // } else {
- view.scapeAdded(new ScapeEvent(this, ScapeEvent.REPORT_ADDED));
- // }
- } catch (TooManyListenersException e) {
- throw new RuntimeException("Tried to add a view to more than one scape:\n" + e);
- }
- if (createFrame && view.isGraphic()) {
- if (!Runner.isServeGraphics()) {
- getEnvironment().addView(view);
- }
- // topdo remove view dependency
- }
- } else {
- }
- }
-
- /**
- * Adds a view to this scape. Takes care of basic housekeeping, including
- * registering view as listener, and creating window for view to be
- * displayed within. An important exception occurs when a GUI view is added
- * and display GUI is set to false. In this case, the view will _not_ be
- * added. This makes it easy to add views in many model components without
- * worrying about checking for GUI display state. Views can be added
- * regardless of the value of display GUI by using addViewForce. Note: Even
- * with the conveneince of this method, it is often nec
- *
- * @param view ComponentView to display in window
- * @param createFrame should the view be placed within a new window frame?
- */
- public synchronized void addView(ScapeListener view, boolean createFrame) {
- addView(view, createFrame, false);
- }
-
- /**
- * Adds a view to this scape. Takes care of basic housekeeping, including
- * registering view as listener, and creating window for view to be
- * displayed within.
- *
- * @param views ComponentView to display in window
- */
- public synchronized void addViews(ScapeListener[] views) {
- this.addViews(views, true);
- }
-
- /**
- * Adds an array of views to this scape. Takes care of basic housekeeping,
- * including registering the views as listeners, and creating window for
- * view to be displayed within. This version of the method allow the adding
- * of a view without regard to the GUI setting. This method might be useful
- * for instace when temporaily instrumenting a non-gui run with diagnostics.
- * Normally addScapeListener should be used.
- *
- * @param views ComponentViews array to display in window
- * @param createFrame should the view be placed within a new window frame?
- * @param forceGUI add a GUI view witout regard to the dispaly GUI setting
- */
- public synchronized void addViews(ScapeListener[] views, boolean createFrame, boolean forceGUI) {
- if (forceGUI || Runner.isDisplayGraphics() || !views[0].isGraphic()) {
- try {
- for (int i = 0; i < views.length; i++) {
- this.addScapeListener(views[i]);
- views[i].scapeAdded(new ScapeEvent(this, ScapeEvent.REPORT_ADDED));
- }
- } catch (TooManyListenersException e) {
- throw new RuntimeException("Tried to add a view to more than one scape");
- }
- boolean allGraphic = false;
- for (int i = 0; i < views.length; i++) {
- if (views[i].isGraphic()) {
- allGraphic = true;
- } else {
- allGraphic = false;
- break;
- }
- }
- // For now, we're going to assume that if one of the views is
- // graphic, they all are
- if (createFrame && allGraphic) {
- getEnvironment().addViews(views);
- }
- }
- }
-
- /**
- * Adds an array of views to this scape. Takes care of basic housekeeping,
- * including registering the views as listeners, and creating window for
- * view to be displayed within. An important exception occurs when GUI views
- * are added and display GUI is set to false. In this case, the views will
- * _not_ be added. This makes it easy to add views in many model components
- * without worrying about checking for GUI display state. Views can be added
- * regardless of the value of dispaly GUI by using addViewForce.
- *
- * @param views ComponentViews to display in window
- * @param createFrame should the view be placed within a new window frame?
- */
- public synchronized void addViews(ScapeListener[] views, boolean createFrame) {
- // To do, test and throw error for case where user tries to add mixed
- // gui and non gui views, or the view array is empty
- addViews(views, createFrame, false);
- }
-
- /**
- * Adds an observer to this scape. This observer will be notified when the
- * scape has finished iterating, and is expected to notify this scape when
- * it has updated itself. This method also adds the scape to the listener as
- * a control listener.
- *
- * @param listener the listern to add
- */
- public synchronized void addScapeListener(ScapeListener listener) {
- if (listener == null) {
- throw new RuntimeException("Tried to add a null listener to Scape.");
- }
- // Not sure if we want to make this poilicy or not..
- /*
- * if (listener.getScape() == null) { throw new
- * RuntimeException("Listener must have this scape assigned before
- * calling addScapeListener."); }
- */
- // change to array copy
- scapeListeners.add(listener);
- updatedListeners++;
- listenerOrMemberUpdated();
- }
-
- /**
- * Adds an observer to this scape. This version simple adds the new listener
- * to the beginning of the list. This can be useful if there are listeners
- * that need to be called first.
- *
- * @param listener the listern to add
- */
- public synchronized void addScapeListenerFirst(ScapeListener listener) {
- if (listener == null) {
- throw new RuntimeException("Tried to add a null listener to Scape.");
- }
- scapeListeners.add(0, listener);
- updatedListeners++;
- listenerOrMemberUpdated();
- }
-
- /**
- * Returns true if and only if the argument is an observer of this scape.
- */
- public boolean isScapeListener(ScapeListener listener) {
- return scapeListeners.contains(listener);
- }
-
- /**
- * Removes the observer from this scape. This observer will be notified when
- * the scape has finished iterating, and is expected to notify this scape
- * when it has updated itself.
- */
- public synchronized void removeScapeListener(ScapeListener listener) {
- boolean success = scapeListeners.remove(listener);
- if (!success) {
- getEnvironment().getConsole().println(
- "WARNING: Tried to remove unregistered scape listener " + listener + " from scape " + this + ".");
- }
-
- listener.scapeRemoved(new ScapeEvent(this, ScapeEvent.REPORT_REMOVED));
- // we may have just removed the last non-updated listener,
- // so that everything needing an update has been updated; we need to
- // check.
- listenerOrMemberUpdated();
- }
-
- /**
- * Returns all listeners for this scape.
- */
- public ArrayList getScapeListeners() {
- return scapeListeners;
- }
-
- // todo (Tried using thread notification, but too slow...perhpas w/
- // pooling??
- // class NotificationThread extends Thread {
- // private ScapeListener listener;
- // private int id;
- //
- // public NotificationThread(ScapeListener listener, int id) {
- // super(Scape.this + " Scape Notify " + listener);
- // this.listener = listener;
- // this.id = id;
- // }
- //
- // public void run() {
- // listener.scapeNotification(new ScapeEvent(Scape.this, id));
- // }
- // }
-
- /**
- * Notifies all scape listeners that this scapes state has changed. The root
- * scape thread then waits until all listeners have been updated.
- */
- public void notifyViews(final int id) {
- notifyViews(new ScapeEvent(Scape.this, id));
- }
-
- /**
- * Notifies all scape listeners that this scapes state has changed. The root
- * scape thread then waits until all listeners have been updated.
- */
- public void notifyViews(final ScapeEvent event) {
- listenersAndMembersCurrent = false;
- updatedListeners = 0;
- updatedMembers = 0;
- if (scapeListeners.size() > 0) {
- ArrayList currentListeners = (ArrayList) scapeListeners.clone();
- for (Object listener : currentListeners) {
- getRunner().notify(event, (ScapeListener) listener);
- }
- } else {
- listenerOrMemberUpdated();
- }
- }
-
- /**
- * Have all views and views of memebers of this scape been updated? [The
- * grammer is terrible, but it fits the text pattern!]
- *
- * @return boolean true if no views are still updating, false if not
- */
- public final boolean isAllViewsUpdated() {
- return listenersAndMembersCurrent;
- }
-
- /**
- * Called whenever a listener or member scape of this scape has been
- * updated. If all listeners and members have been updated, informs parent
- * scape.
- */
- protected synchronized void listenerOrMemberUpdated() {
- // For testing updating..
- // if ((updatedListeners >= scapeListeners.length) &&
- // ((!(getPrototypeAgent() instanceof Scape)) || (!(((Scape)
- // getPrototypeAgent()).isMembersActive())) || (!(getPrototypeAgent()
- // instanceof AgentScape)) || (updatedMembers >= getSize()))) {
- if (updatedListeners >= scapeListeners.size()
- && (updatedMembers >= getSize() || !(getPrototypeAgent() instanceof Scape)
- || getSpace() instanceof Singleton || !((Scape) getPrototypeAgent()).isMembersActive())) {
- listenersAndMembersCurrent = true;
- updatedListeners = 0;
- updatedMembers = 0;
- if (scape != null) {
- scape.memberUpdated(this);
- // if (isInitialized() ) {
- // getRuntimeEnvironment().getConsole().println(scape.
- // updatedListeners
- // + "/" +
- // scape.scapeListeners.length + ", " + scape.updatedMembers +
- // "/"+scape.getSize() + " for " + scape + " from " + this);
- // }
- }
- }
- }
-
- /**
- * Called whenever a listener has been updated.
- *
- * @param listener the listener tha has been updated
- */
- public synchronized void listenerUpdated(ScapeListener listener) {
- updatedListeners++;
- // Useful for testing updating problems.
- // getRuntimeEnvironment().getConsole().println("L " + listener + ": " +
- // updatedListeners +" of "+ scapeListeners.size()+" ---
- // "+updatedMembers + " of
- // " + getSize());
- listenerOrMemberUpdated();
- }
-
- /**
- * Called whenever a member has been updated.
- *
- * @param member the member that has been updated
- */
- public synchronized void memberUpdated(Scape member) {
- updatedMembers++;
- // Useful for testing updating problems.
- // getRuntimeEnvironment().getConsole().println("M " + member + ": " +
- // updatedListeners +" of "+ scapeListeners.size()+" ---
- // "+updatedMembers + " of
- // " + getSize());
- listenerOrMemberUpdated();
- }
-
- /**
- * Responds to any control events fired at this scape. Currently reacts to
- * start, stop, pause, resume, step, quit, and restart events, as well as
- * listener update report events. All control events except listener updates
- * are passed up to the root. Any other events trigger an untrapped
- * exception.
- */
- public void respondControl(ControlEvent control) {
- if (control.getID() == ControlEvent.REPORT_LISTENER_UPDATED) {
- listenerUpdated((ScapeListener) control.getSource());
- } else {
- getRunner().respondControl(control);
- }
- }
-
- /**
- * This is for grid communication of changes in draw feature.
- *
- * @param event
- */
- public void respondDrawFeature(DrawFeatureEvent event) {
- throw new RuntimeException("The client or worker scape should define their own version of this!");
- }
-
- /**
- * Sets the running state for all scapes. Safe to call on any scape in the
- * model; the request is propogated to the parent scape. If true, starts the
- * parent scape's thread, which causes scape to iterate. If set false, the
- * scape will be stopped when the current iteration is complete.
- *
- * @param running if true, starts the thread, if false, stops it.
- */
- public void setRunning(boolean running) {
- getRunner().setRunning(running);
- }
-
- /**
- * Has the scape been requested to run? <i>Note:</i> if false, indicates
- * that a stop has been requested, not neccesarily that it has occured, as
- * the simulation continues the current iteration. If you need to know when
- * a scape has actually stopped, listen for the scapeStopped event.
- *
- * @return the current requested running state
- */
- public boolean isRunning() {
- return getRunner() != null && getRunner().isRunning();
- }
-
- /**
- * Sets the paused state for all parent and member scapes. Safe to call on
- * any scape in the model; the request is propogated up to the parent scape.
- * If set true, a pause will occur when the current iteration is complete.
- *
- * @param pause if true, pauses, otherwise resumes iterations
- */
- public void setPaused(boolean pause) {
- if (pause) {
- getRunner().pause();
- } else {
- getRunner().resume();
- }
- }
-
- /**
- * Has the scape been requested to pause? <i>Note:</i> indicates that a
- * pause has been requested, not neccesarily that the simulation is paused;
- * it may be completing its current iteration.
- *
- * @return true if pause requested, false if resume requested or running
- * normally
- */
- public boolean isPaused() {
- return getRunner().isPaused();
- }
-
- /**
- * Sets the earliest period this scape is expected to be run at. 0 by
- * default.
- *
- * @param earliestPeriod the lowest period value this scape can have
- */
- public void setEarliestPeriod(int earliestPeriod) {
- getRunner().setEarliestPeriod(earliestPeriod);
- }
-
- /**
- * Sets the latest period this scape is expected to be run at. Max of
- * integer (effectively unlimited) by default.
- *
- * @param latestPeriod the highest period value this scape can have
- */
- public void setLatestPeriod(int latestPeriod) {
- getRunner().setLatestPeriod(latestPeriod);
- }
-
- /**
- * Is the supplied period a valid period for this scape?
- *
- * @param period the period to test
- * @return true if within earliest and latest periods, false otherwise
- */
- public boolean isValidPeriod(int period) {
- return getRunner().isValidPeriod(period);
- }
-
- /**
- * Returns the period this scape begins running at. By default, the greater
- * of earliest period and 0.
- */
- public int getStartPeriod() {
- return getRunner().getStartPeriod();
- }
-
- /**
- * Sets the start period for this scape. The start period is the period this
- * scape is given when a model run is started.
- *
- * @param startPeriod the period to begin runs at
- */
- public void setStartPeriod(int startPeriod) throws SpatialTemporalException {
- getRunner().setStartPeriod(startPeriod);
- }
-
- /**
- * Returns the period this scape stops running at. By default, the lesser of
- * latest period and integer maximum value (effectively unlimited.)
- */
- public int getStopPeriod() {
- return getRunner().getStopPeriod();
- }
-
- /**
- * Sets the stop period for this scape. The stop period is the period that
- * the scape is automatically stopped at. The scape may be automatically set
- * to start agina at start value is the scape is set to restart.
- *
- * @param stopPeriod the period the scape will stop at upon reaching
- * @see #setAutoRestart
- */
- public void setStopPeriod(int stopPeriod) throws SpatialTemporalException {
- getRunner().setStopPeriod(stopPeriod);
- }
-
- /**
- * Returns the period to pause on.
- */
- public int getPausePeriod() {
- return getRunner().getPausePeriod();
- }
-
- /**
- * Causes the model to pause at the specified period.
- *
- * @param pausePeriod when to pause
- */
- public void setPausePeriod(int pausePeriod) {
- getRunner().setPausePeriod(pausePeriod);
- }
-
- /**
- * Does the scape automatically start upon opening? True by default.
- */
- public boolean isStartOnOpen() {
- return Runner.isStartOnOpen();
- }
-
- /**
- * Should the scape be automatically started upon opening? True by default.
- *
- * @param startOnOpen true to start the scape upon opening a model
- */
- public void setStartOnOpen(boolean startOnOpen) {
- Runner.setStartOnOpen(startOnOpen);
- }
-
- /**
- * Should the scape be automatically restarted upon stopping at its stop
- * period? Setting this value to true allows easy cycling of models for
- * demonstrations, model explorations, etc. See DataOutputView for an
- * example of more sophisticated handling of multiple runs.
- *
- * @param autoRestart true to restart the scape upon reaching stop period,
- * false to simple stop
- * @see #setStopPeriod
- */
- public void setAutoRestart(boolean autoRestart) {
- getRunner().setAutoRestart(autoRestart);
- }
-
- /**
- * Returns the root of this scape, which may be this scape. This was an
- * older usage and is retained for backward compatability only. It is now
- * not a all good name as it confuses model for a view / control component,
- * and may be removed in the future.
- *
- * @deprecated please use #getRunner().
- */
- public Runner getModel() {
- return getRunner();
- }
-
- /**
- * Returns the runtime model environment, which manages model-wide state
- * such as run status.
- *
- * @return the model environment for entire model
- */
- public Runner getRunner() {
- return getRoot().runner;
- }
-
- public void setRunner(Runner _runner) {
- runner = _runner;
- }
-
- /**
- * Returns the path in which all files should by default be stored to and
- * retrieved from. Nonstatic, so that parameter can automatically be set
- * from command line, but backing variable is static. Default is "./", can
- * be modified by calling setHome or providing an ascape.home java property.
- * (This may change now since it is no longer neccesary.)
- */
- public String getHome() {
- return getRunner().getHome();
- }
-
- /**
- * Sets the path in which to store all scape related files. Nonstatic, so
- * that parameter can automatically be set from command line, but backing
- * variable is static.
- *
- * @param home the fully qualified path name for this scape
- */
- public void setHome(String home) {
- getRunner().setHome(home);
- }
-
- /**
- * Are members of this active scape model participants, that is, do they
- * have rules executed upon them? Default is true.
- *
- * @return true if members actively execute rules, false otherwise
- */
- public boolean isMembersActive() {
- return membersActive;
- }
-
- /**
- * Sets whether members of this scape actively execute rules upon members.
- *
- * @param membersActive true if members actively execute rules, false
- * otherwise
- */
- public void setMembersActive(boolean membersActive) {
- this.membersActive = membersActive;
- }
-
- /**
- * Do cells request view updates manually or are all cells automatically
- * updated every view cycle? While requiring cells to request updates
- * manually adds a little to complication to model design and maintenance,
- * manual requests allow a significant boost in view performance, as all
- * cells do not have to be drawn every cycle. False by default.
- *
- * @return true if cells must request updates, false if cell updates handled
- * automatically
- */
- public boolean isCellsRequestUpdates() {
- return cellsRequestUpdates;
- }
-
- /**
- * Should cells request view updates manually or are all cells automatically
- * updated every view cycle? See above. <i>Important:</i> If you set this
- * value to be true, you are responsible for ensuring that the
- * <code>requestUpdate</code> method is called anytime a cell's state
- * changes such that a view may be affected. Some of these calls will be
- * handled for you automatically, for instance, it is not neccesary to call
- * requestUpdate when a cell moves, since the HostCell calls requestUpdates
- * for you. Typically, you will need to request updates when the internal
- * state of a cell changes and that is reflected in how a cell is
- * represeneted in a view, for example, if you color an agent for wealth,
- * you will need to call <code>requestUpdate</code> anytime the agent wealth
- * changes.
- *
- * @param cellsRequestUpdates if cells should request updates, false if cell
- * updates should be handled automatically
- * @see Cell#requestUpdate
- */
- public void setCellsRequestUpdates(boolean cellsRequestUpdates) {
- this.cellsRequestUpdates = cellsRequestUpdates;
- }
-
- /**
- * Executes the provided rules on the supplied agentArray.
- */
- public void execute(List rules, List agents) {
- Agent[] agentArray = new Agent[agents.size()];
- agents.toArray(agentArray);
- int[] order = CollectionSpace.createOrder(agentArray.length);
- if (executionOrder == AGENT_ORDER) {
- order = CollectionSpace.randomizeOrder(order, getRandom());
- for (int i = 0; i < agentArray.length; i++) {
- for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
- Rule rule = (Rule) iterator.next();
- rule.execute(agentArray[order[i]]);
- }
- }
- } else { // executionOrder == RULE_ORDER
- // Add call so that cells can respond even if this is not the
- // primary agent
- for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
- Rule rule = (Rule) iterator.next();
-
- if (rule.isRandomExecution()) {
- order = CollectionSpace.randomizeOrder(order, getRandom());
- }
- for (int i = 0; i < agentArray.length; i++) {
- rule.execute(agentArray[order[i]]);
- }
- if (rule instanceof ExecuteThenUpdate) {
- if (rule.isRandomExecution()) {
- order = CollectionSpace.randomizeOrder(order, getRandom());
- }
- for (int i = 0; i < agentArray.length; i++) {
- ((ExecuteThenUpdate) rule).update(agentArray[order[i]]);
- }
- }
- }
- }
- }
-
- /**
- * Executes the provided rule on every member of the lattice, according to
- * the rule settings and the execution order of this scape.
- */
- public void execute(Rule rule, List agents) {
- List rules = new ArrayList(1);
- rules.add(rule);
- execute(rules, agents);
- }
-
- /**
- * Executes all of this scapes selected rules on its members.
- */
- public void executeOnMembers() {
- executeOnMembers(rules);
- }
-
- /**
- * Executes the provided rules on every member of the lattice, according to
- * the rule settings and the execution order of this scape.
- */
- public void executeOnMembers(VectorSelection ruleSelection) {
- executeOnMembers(ruleSelection.getSelection());
- }
-
- /**
- * Executes the provided rule on every member of the lattice, according to
- * the rule settings and the execution order of this scape.
- */
- public void executeOnMembers(Rule rule) {
- Rule[] rules = new Rule[1];
- rules[0] = rule;
- executeOnMembers(rules);
- }
-
- /**
- * Executes the provided rules on every member of the collection, according
- * to the rule settings and the execution order of the scape.
- */
- public void executeOnMembers(Object[] rules) {
- if (rules.length > 0) {
- strategy = new StrategyFactory(this, rules, Scape.threadCount).getStrategy();
- strategy.execute();
- }
- }
-
- /**
- * Returns an iterator across all agents in this scape. Note that this is
- * simply an iterator of the backing collections members. It will have
- * different behavior than is typically desried when iterating behavior
- * across a scape*; so for instance, this method is not used by the internal
- * rule mechanism. It should be perfectly adequete for tight iterations
- * across agents when there are no additions or deletions during the
- * iteration; for instance, when calcualting some value across a number of
- * agents. *The iterator will not be aware of an agents deletion from the
- * scape after its creation; this is because the scape caches these removals
- * to improve performance. It may include agents that are added to the scape
- * after its creation, and this is typically not desirable behavior when
- * touring a collection of current agents.
- *
- * @return an iterator over the agents in scape order
- */
- public Iterator iterator() {
- return space.iterator();
- }
-
- /**
- * Propogates the rule for execution up to the root of the scape tree, then
- * propogates down to all nodes.
- */
- public void executeOnRoot(Rule[] rules) {
- if (scape == null) {
- // Top level, so execute for all nodes
- execute(rules);
- } else {
- // Still have parent scapes, so propogate up
- scape.executeOnRoot(rules);
- }
- }
-
- /**
- * Propogates the rule for execution up to the root of the scape tree, then
- * propogates down to all nodes.
- */
- public void executeOnRoot(Rule rule) {
- Rule[] rules = new Rule[1];
- rules[0] = rule;
- executeOnRoot(rules);
- }
-
- /**
- * Holds the current search rule. Make non-static to make searching
- * threadsafe.
- */
- private static SearchRule defaultSearch;
-
- /**
- * Searches through the scape for an object (agent) that matches the
- * supplied key and comparator. Typically will return the first agent found,
- * but this behavior is not guranteed. For now, this is implemented as a
- * simple linear search, so search time is O(n). Future versions may allow
- * use of a binary search where the scape is allready appropriatly sorted,
- * or may allow a cached comparator map to be used. For now if the scape is
- * sorted in an order matching the comparators order, you can use
- * "getAsList" and Collections.binarySearch to get an O(log(n)) search. This
- * code is not thread safe, but can easily be made so.
- *
- * @param comparator the Comparator to use to perfrom the search
- * @param key the key that an agent must match in order to be returned.
- */
- public Agent search(Comparator comparator, Object key) {
- if (defaultSearch == null) {
- defaultSearch = new SearchRule("Default Scape Search Rule");
- }
- defaultSearch.setComparator(comparator);
- defaultSearch.setKey(key);
- defaultSearch.setSearchType(SearchRule.SEARCH_EQUAL);
- defaultSearch.clear();
- executeOnMembers(defaultSearch);
- return defaultSearch.getFoundAgent();
- }
-
- /**
- * Searches through the scape for an object (agent) that has the minimum
- * value as defined by the comparator.
- *
- * @param comparator the Comparator to use to determin the minimum
- */
- public Agent searchMin(Comparator comparator) {
- if (defaultSearch == null) {
- defaultSearch = new SearchRule("Default Scape Search Rule");
- }
- defaultSearch.setComparator(comparator);
- defaultSearch.setSearchType(SearchRule.SEARCH_MIN);
- defaultSearch.clear();
- executeOnMembers(defaultSearch);
- return defaultSearch.getFoundAgent();
- }
-
- /**
- * Searches through the scape for an object (agent) that has the minimum
- * value as defined by the comparator.
- *
- * @param comparator the Comparator to use to determin the minimum
- */
- public Agent searchMax(Comparator comparator) {
- if (defaultSearch == null) {
- defaultSearch = new SearchRule("Default Scape Search Rule");
- }
- defaultSearch.setComparator(comparator);
- defaultSearch.setSearchType(SearchRule.SEARCH_MAX);
- defaultSearch.clear();
- executeOnMembers(defaultSearch);
- return defaultSearch.getFoundAgent();
- }
-
- /**
- * If true, turns on value (typically for statistics) collection, else turns
- * off stat collection.
- */
- public void setCollectStats(boolean collect) {
- if (collect) {
- collectStats = new CollectStats();
- collectStats.setScape(this);
- } else {
- collectStats = null;
- }
- }
-
- /**
- * Returns the value collection rule in effect; null if no value collection.
- */
- public CollectStats getCollectStats() {
- return collectStats;
- }
-
- /**
- * Sets the value collection rule to the one supplied. Allows use of custom
- * value collection rules. Please let me know if you use this..considering
- * removal.
- */
- public void setCollectStats(CollectStats collectStats) {
- this.collectStats = collectStats;
- collectStats.setScape(this);
- }
-
- /**
- * Is the scape responsible for creating itself and its members, or are
- * other classes responsible for creating the scape? If true (default) calls
- * the createScape method on model construction, typically causing the scape
- * to be populated with clones of prototype agent. If false, scape must be
- * populated manually.
- */
- public boolean isAutoCreate() {
- return autoCreate;
- }
-
- /**
- * Sets wether the scape is responsible for creating itself and its members,
- * or other model components handle this.
- *
- * @param autoCreate if true calls createScape at construction, otherwise
- * model is built manually
- */
- public void setAutoCreate(boolean autoCreate) {
- this.autoCreate = autoCreate;
- }
-
- /**
- * Is the scape populated when the scape is created? That is, is the
- * populate scape method called when create scape is executed? (Typically,
- * the populate scape method will fill each cell with clones of the
- * prototype cell, but of course this behavior can be overidden.) True by
- * default.
- *
- * @return true if the scape will be populated when scape create is called,
- * false otherwise
- */
- public boolean isPopulateOnCreate() {
- return populateOnCreate;
- }
-
- /**
- * Sets wether the scape is responsible for populating itself.
- *
- * @param populateOnCreate if true calls createScape at construction,
- * otherwise model is built manually
- */
- public void setPopulateOnCreate(boolean populateOnCreate) {
- this.populateOnCreate = populateOnCreate;
- }
-
- /**
- * Adds the specified stat collectors to this scape for automatic collection
- * by the scape. If this scape is not allready collecting stats, implicitly
- * sets collect stats to true. Adds the stats to the stat collection rule.
- *
- * @param stats the stat collectors to add to this scape.
- */
- public void addStatCollectors(StatCollector[] stats) {
- // stats added in collect values
- // getData().addStatCollectors(StatCollectors);
-
- // loop through and give the stats references for their datagroup.
- // must be done prior to getData().add(stats), because
- // DataGroup.add(Stats)
- // calls getAllDataSeries, which calls isCollectingLongitudinal, which
- // uses the StatCollector's
- // reference to its data group.
- for (int i = 0; i < stats.length; i++) {
- stats[i].setDataGroup(getRunner().getData());
- }
- getRunner().getData().add(stats);
- if (collectStats == null) {
- setCollectStats(true);
- }
- collectStats.addStatCollectors(stats);
- }
-
- /**
- * Adds the specified stat collector iff and only if it hasn't allready been
- * added.
- *
- * @param stat the stat collector to add to this scape. todo allow
- * replacement (cuurent version only adds if a stat does not
- * already exist.) possibly get rid of this once issue with
- * multiple stat collectors is resolved.
- */
- public StatCollector addStatCollectorIfNew(StatCollector stat) {
- StatCollector foundStat = getRunner().getData().getStatCollector(stat.getName());
- if (foundStat == null) {
- addStatCollector(stat);
- foundStat = stat;
- }
- return foundStat;
- }
-
- /**
- * Adds the specified stat collector to this scape for automatic collection
- * by the scape. If this scape is not allready collecting stats, implicitly
- * sets collect stats to true. Adds the stat to the stat collection rule.
- *
- * @param stat the stat collector to add to this scape.
- */
- public void addStatCollector(StatCollector stat) {
- StatCollector[] stats = new StatCollector[1];
- stats[0] = stat;
- addStatCollectors(stats);
- }
-
- /**
- * Returns the stat collectors currently calcualting stats for this scape.
- */
- public StatCollector[] getStatCollectors() {
- if (collectStats != null) {
- return collectStats.getStatCollectors();
- } else {
- throw new RuntimeException("Tried to get stats but they are not being collected");
- }
- }
-
- /**
- * Just a class for a delegated proxy for draw features.
- */
- public class DrawFeatureObservable extends Observable implements Serializable {
-
- /**
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Iterate over every member and child.
+ *
+ * @param agent
+ * the target agent
+ */
+ public void execute(Agent agent) {
+ CollectStats collectStats = ((Scape) agent).getCollectStats();
+ // Special case for value collection rule
+ if (collectStats != null) {
+ /*
+ * int iterations = ScapeDiscrete.ALL_AGENTS; if (agent instanceof
+ * ScapeDiscrete) { iterations = ((ScapeDiscrete)
+ * agent).getAgentsPerIteration(); ((ScapeDiscrete)
+ * agent).setAgentsPerIteration(ScapeDiscrete.ALL_AGENTS); }
+ */
+ collectStats.setPhase(1);
+ ((Scape) agent).executeOnMembers(collectStats);
+ collectStats.setPhase(2);
+ ((Scape) agent).executeOnMembers(collectStats);
+ /*
+ * if (agent instanceof ScapeDiscrete) { ((ScapeDiscrete)
+ * agent).setAgentsPerIteration(iterations); }
+ */
+ }
+ super.execute(agent);
+ if (collectStats != null) {
+ collectStats.calculateValues();
+ }
+ if (((Scape) agent).isRoot() && ((Scape) agent).getRunner().getData() != null) {
+ ((Scape) agent).getRunner().getData().update();
+ // System.gc();
+ }
+ }
+ };
+
+ /**
+ * The symbol to execute rules against all agents in each iteration.
+ */
+ public final static int ALL_AGENTS = -1;
+
+ /**
+ * Symbol for by agent execution order.
+ */
+ public final static int AGENT_ORDER = -2;
+
+ /**
+ * Symbol for by rule execution order.
+ */
+ public final static int RULE_ORDER = -1;
+
+ /**
+ * Symbol for complete tour excution style.
+ */
+ public final static int COMPLETE_TOUR = 1;
+
+ /**
+ * Symbol for repeated random draw execution style.
+ */
+ public final static int REPEATED_DRAW = 2;
+
+ /**
+ * Manages time, model-wide views and other features that are shared between
+ * scapes. There is one an only one for each model instance.
+ */
+ private Runner runner;
+
+ private Space space;
+
+ /**
+ * An agent which which may be cloned to produce members of this collection.
+ * By default, all scapes which have a known number of members are initialized
+ * with clones of this agent.
+ */
+ protected Agent prototypeAgent;
+
+ /**
+ * The rules that this scape will execute on its memebers.
+ */
+ private VectorSelection rules = new VectorSelection(new Vector());
+
+ /**
+ * The rules that this scape will execute on its members upon initializtion.
+ */
+ protected VectorSelection initialRules = new VectorSelection(new Vector());
+
+ /**
+ * The observers of this scape. All listeners are notified when the scape is
+ * updated and given a chance to update themselves.
+ */
+ private ArrayList<ScapeListener> scapeListeners = new ArrayList<ScapeListener>();
+
+ /**
+ * The number of agents to execute each rule across for each iteration.
+ */
+ protected int agentsPerIteration = ALL_AGENTS;
+
+ /**
+ * Order in which rules should be executed.
+ */
+ private int executionOrder = AGENT_ORDER;
+
+ /**
+ * 'Stlye' of rule execution.
+ */
+ private int executionStyle = COMPLETE_TOUR;
+
+ /**
+ * Should members of the scape be iterated against?
+ */
+ private boolean membersActive = true;
+
+ /**
+ * Should members of the scape be automatically created at startup?
+ */
+ private boolean autoCreate = true;
+
+ /**
+ * Should the scape be populated on creation?
+ */
+ private boolean populateOnCreate = true;
+
+ /**
+ * Should cells indicate that they need to be updated manually (imroving
+ * performance significantly) or should all cells be updated every iteration.
+ */
+ private boolean cellsRequestUpdates = false;
+
+ /**
+ * The value collection rule for this scape. Null if no values should be
+ * collected.
+ */
+ private CollectStats collectStats = null;
+
+ /**
+ * A view of the scape that delegates back to the scape, often null.
+ * Automatically created for root when standard model is used.
+ */
+ private ScapeListener selfView;
+
+ /**
+ * A vector of features available to draw memebers of this scape.
+ */
+ private Vector drawFeatures = new Vector();
+
+ /**
+ * Are all the listeners and members (which may have listeners) of this scape
+ * current? (If so, we can continue updating, otherwise, we must wait.
+ */
+ private boolean listenersAndMembersCurrent = false;
+
+ /**
+ * Determines how many time steps pass between updating displayed charts and
+ * graphs. Higher numbers result in faster performance but less frequent
+ * updates. This setting does not affect model results.
+ */
+ private int iterationsPerRedraw = 1;
+
+ /**
+ * Count of the number of listeners that have been updated. Used to determine
+ * when all listeners have been updated.
+ */
+ private int updatedListeners = 0;
+
+ /**
+ * Count of the number of members that have been updated. Used to determine
+ * when all members have been updated.
+ */
+ private int updatedMembers = 0;
+
+ private boolean serializable = true;
+
+ /**
+ * Constructs a scape with default list topology.
+ */
+ public Scape() {
+ this(new ListSpace());
+ }
+
+ /**
+ * Constructs a scape.
+ *
+ * @param space
+ * the topology for this scape
+ */
+ public Scape(CollectionSpace space) {
+ this(space, null, null);
+ }
+
+ /**
+ * Constructs a scape of provided geometry, to be populated with clones of
+ * provided agent.
+ *
+ * @param name
+ * a descriptive name for the scape
+ * @param prototypeAgent
+ * the agent whose clones will be used to populate this scape
+ */
+ public Scape(String name, Agent prototypeAgent) {
+ this(null, name, prototypeAgent);
+ }
+
+ /**
+ * Constructs a scape of provided geometry, to be populated with clones of
+ * provided agent.
+ *
+ * @param name
+ * a descriptive name for the scape
+ * @param prototypeAgent
+ * the agent whose clones will be used to populate this scape
+ * @param space
+ * the topology for this scape
+ */
+ public Scape(CollectionSpace space, String name, Agent prototypeAgent) {
+ super();
+ setSpace(space);
+ setName(name);
+ setPrototypeAgent(prototypeAgent);
+ scapeListeners = new ArrayList();
+ listenersAndMembersCurrent = true;
+ }
+
+ /**
+ * Returns the size, or number of agents, of this Scape.
+ */
+ public int getSize() {
+ return space.getSize();
+ // return vector.size();
+ }
+
+ /**
+ * Sets the prototype agent, the agent that, in default implementations, will
+ * be cloned to populate this scape. It is an error to call while the scape is
+ * running.
+ *
+ * @param prototypeAgent
+ * the agent whose clones will populate this scape
+ */
+ public void setPrototypeAgent(Agent prototypeAgent) {
+ this.prototypeAgent = prototypeAgent;
+ if (prototypeAgent != null && prototypeAgent.getScape() == null) {
+ prototypeAgent.setScape(this);
+ prototypeAgent.scapeCreated();
+ }
+ setInitialized(false);
+ }
+
+ /**
+ * Returns the agent that is cloned to populate this scape.
+ */
+ public Agent getPrototypeAgent() {
+ return prototypeAgent;
+ }
+
+ /**
+ * Returns the number of agents to iterate through each iteration cycle.
+ * *@param returns the number of iterations per cycle
+ */
+ public int getAgentsPerIteration() {
+ return agentsPerIteration;
+ }
+
+ /**
+ * Sets the number of agents to iterate through each iteration cycle. By
+ * default, set to iterate through all agents. *@param agentsPerIteration the
+ * number of agents to iterate against per cycle, ALL_AGENTS for all agents
+ */
+ public void setAgentsPerIteration(int agentsPerIteration) {
+ this.agentsPerIteration = agentsPerIteration;
+ }
+
+ /**
+ * Returns the number of iterations to perform before updating views.
+ */
+ public int getIterationsPerRedraw() {
+ return iterationsPerRedraw;
+ }
+
+ /**
+ * Sets the number of iterations to perform before updating views, and
+ * propagates this setting to all scapes and views in the model.
+ */
+ public void setIterationsPerRedraw(int iterationsPerRedraw) {
+ setIterationsPerRedraw(iterationsPerRedraw, true);
+ }
+
+ /**
+ * Sets the number of iterations to perform before updating views, and
+ * optionally propagates this setting to all scapes and views in the model.
+ */
+ public void setIterationsPerRedraw(int iterationsPerRedraw, boolean propagate) {
+ this.iterationsPerRedraw = iterationsPerRedraw;
+ if (propagate) {
+ executeOnRoot(new NotifyViews(ScapeEvent.REQUEST_CHANGE_ITERATIONS_PER_REDRAW) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void execute(Agent agent) {
+ ((Scape) agent).setIterationsPerRedraw(agent.getRoot().getIterationsPerRedraw(), false);
+ super.execute(agent);
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns the execution order that has been set for this scape.
+ */
+ public int getExecutionOrder() {
+ return executionOrder;
+ }
+
+ /**
+ * Sets the order of rule execution for this scape. If 'rule order', each rule
+ * is executed on every agent in turn. If 'agent order', every rule is
+ * executed on each agent in turn. Execution order can be profoundly
+ * significant to a model's dynamics. For 'synchrounous' style rules that
+ * subclass ExecuteAndUpdate, 'by rule' execution is the only order that makes
+ * sense.
+ *
+ * @param symbol
+ * RULE_ORDER for by rule execution, AGENT_ORDER for by agent
+ * execution
+ */
+ public void setExecutionOrder(int symbol) {
+ this.executionOrder = symbol;
+ }
+
+ /**
+ * Returns the execution style that has been set for this scape.
+ */
+ public int getExecutionStyle() {
+ return executionStyle;
+ }
+
+ /**
+ * Sets the style that rules will be executed upon this scape. If complete
+ * tour, every agent is visited once and only once (assuming agents per
+ * iteration is set to 'all agents'.) If repeated draw, a random agent is
+ * picked n times for execution. (Actually, if execution order is by agent,
+ * each rule is then executed upon the picked agent, so that there are n total
+ * draws. But if execution order is by rule, then for each rule, a random
+ * agent is picked, which means that there are actually (rules X n) draws. In
+ * practice, this combination does not seem to make much sense in any case.) A
+ * complete tour style of execution seems generally more plausible, but a
+ * repeated draw approach can produce different and interesting results.
+ *
+ * @param symbol
+ * one of COMPLETE_TOUR or REPEATED_DRAW
+ */
+ public void setExecutionStyle(int symbol) {
+ this.executionStyle = symbol;
+ }
+
+ /**
+ * Returns the extent of the scape. The extent can be thought of as the most
+ * extreme point in the scape. For discrete scape's this will simply be the
+ * furthest cell, so that for a 20x20 grid, the extent would be {20, 20}. For
+ * continuous spaces it will be the maximum boundary of the space. For lists,
+ * it will be the size of lists. Therefore, this method should net be confused
+ * with the scape's "size". Note that scape graphs will not have useful
+ * extents, but all other scapes do.
+ */
+ public Coordinate getExtent() {
+ return space.getExtent();
+ }
+
+ /**
+ * Sets the size of the scape. Note that scape graphs will not have useful
+ * extents, but all other scapes do. It is an error to set extent while a
+ * scape is running.
+ *
+ * @param extent
+ * a coordinate at the maximum extent
+ */
+ public void setExtent(Coordinate extent) {
+ if (getRunner() != null && getRunner().isRunning()) {
+ throw new RuntimeException("Tried to modfiy extent while scape was running");
+ }
+ space.setExtent(extent);
+ }
+
+ /**
+ * Sets the size of the scape. Note that scape graphs will not have useful
+ * extents, but all other scapes do. It is an error to set extent while a
+ * scape is running.
+ *
+ * @throws RuntimeException
+ * if the scape is currently running
+ * @param xval
+ * coordinate 1 of the extent
+ */
+ public void setExtent(int xval) {
+ if (runner != null && runner.isRunning()) {
+ throw new RuntimeException("Tried to modfiy extent while scape was running");
+ }
+ if (getSpace().getGeometry().getDimensionCount() != 1) {
+ throw new RuntimeException("Tried to set extent as 1-dimension for a scape that isn't 1-dimensional.");
+ }
+ ((CollectionSpace) getSpace()).setExtent(xval);
+ }
+
+ /**
+ * Sets the size of the scape. Note that scape graphs will not have useful
+ * extents, but all other scapes do. It is an error to set extent while a
+ * scape is running.
+ *
+ * @param xval
+ * coordinate 1 of the extent
+ * @param yval
+ * coordinate 2 of the extent
+ * @throws RuntimeException
+ * if the scape is currently running
+ * @throws UnsupportedOperationException
+ * if the underlying space isn't appropriate
+ */
+ public void setExtent(int xval, int yval) {
+ if (runner != null && runner.isRunning()) {
+ throw new RuntimeException("Tried to modfiy extent while scape was running");
+ }
+ try {
+ ((Array2DBase) getSpace()).setExtent(xval, yval);
+ } catch (ClassCastException e) {
+ throw new UnsupportedOperationException("Can't set extent as x, y; underlying scape doesn't support it.");
+ }
+ }
+
+ /**
+ * Returns the name of this scape, the model name if this is root and there is
+ * no name set.
+ */
+ public String getName() {
+ if (name != null) {
+ return name;
+ } else {
+ return getClass().getName();
+ }
+ }
+
+ private void loadDescriptions() {
+ if (getRunner().getDescription() == null || getRunner().getHTMLDescription() == null) {
+ String fileName = "About" + Utility.getClassNameOnly(this.getClass()) + ".html";
+ URL aboutFile = this.getClass().getResource(fileName);
+ if (aboutFile != null) {
+ getRunner().setDescription("");
+ try {
+ BufferedInputStream is = (BufferedInputStream) aboutFile.getContent();
+ BufferedReader ir = new BufferedReader(new InputStreamReader(is));
+ String nextLine = ir.readLine();
+ // Clean out html tags
+ StringBuffer htmlFragBuffer = new StringBuffer();
+ while (nextLine != null) {
+ htmlFragBuffer.append(nextLine);
+ nextLine = ir.readLine();
+ }
+ StringBuffer plainTextBuffer = new StringBuffer();
+ // Neccessary to support 1.3
+ String htmlString = htmlFragBuffer.toString();
+ boolean done = false;
+ int pos = 0;
+ while (!done) {
+ int anglePos = htmlString.indexOf("<", pos);
+ if (anglePos >= 0) {
+ plainTextBuffer.append(htmlFragBuffer.substring(pos, anglePos));
+ if (htmlFragBuffer.substring(anglePos, anglePos + 4).equalsIgnoreCase("<BR>")) {
+ plainTextBuffer.append("\n");
+ }
+ pos = htmlString.indexOf(">", anglePos) + 1;
+ } else {
+ plainTextBuffer.append(htmlFragBuffer.substring(pos, htmlFragBuffer.length()));
+ done = true;
+ }
+ }
+ setHTMLDescription(htmlFragBuffer.toString());
+ setDescription(plainTextBuffer.toString());
+ } catch (java.io.IOException e) {
+ // Probably file has not been defined; in any case, just use
+ // toString value..
+ getEnvironment().getConsole().println("Non-critical exception: couldn't read \"About\" file: " + e);
+ getRunner().setDescription(toString());
+ }
+ } else {
+ // No about file defined
+ getRunner().setDescription(toString());
+ }
+ }
+ }
+
+ /**
+ * Returns a long (paragraph length suggested) description of the scape. The
+ * root scape should describe the model as a whole; subscapes should describe
+ * themselves. Plantext. If no description is provided, return the standar
+ * toString() description. This description is automatically loaded from a
+ * file called "About[ModelClassName].html" located in the the same directory
+ * as the .class file for the model, if such a file exists. To use this
+ * feature simply create such a file and place it in the appropriate
+ * directory. You can include any normal html style tags in this file, they
+ * will be stripped from the non-html description.
+ */
+ public String getDescription() {
+ try {
+ loadDescriptions();
+ return getRunner().getDescription();
+ } catch (ClassCastException cce) {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a long (paragraph length suggested) description of the scape. The
+ * root scape should describe the model as a whole; subscapes should describe
+ * themselves. If no description is provided, return the standar toString()
+ * description.
+ */
+ public void setDescription(String description) {
+ getRunner().setDescription(description);
+ }
+
+ /**
+ * Returns a long (paragraph length suggested) description of the scape. The
+ * root scape should describe the model as a whole; subscapes should describe
+ * themselves. Includes html tags as appropriate. This description is
+ * automatically loaded from a file called "About[ModelClassName].html"
+ * located in the the same directory as the .class file for the model, if such
+ * a file exists. To use this feature simply create such a file and place it
+ * in the appropriate directory. You can include any normal html style tags in
+ * this file, they will be stripped from the non-html description. If no
+ * description is provided, return the standar toString() description.
+ */
+ public String getHTMLDescription() {
+ loadDescriptions();
+ return getRunner().getHTMLDescription();
+ }
+
+ /**
+ * Returns a long (paragraph length suggested) description of the scape. The
+ * root scape should describe the model as a whole; subscapes should describe
+ * themselves. Should include html tags as appropriate. If no description is
+ * provided, return the standar toString() description.
+ */
+ public void setHTMLDescription(String description) {
+ getRunner().setHTMLDescription(description);
+ }
+
+ /**
+ * Returns the root of this scape, which may be this scape.
+ */
+ public final Scape getRoot() {
+ if (scape == null) {
+ return this;
+ } else {
+ return scape.getRoot();
+ }
+ }
+
+ /**
+ * Is this scape the root within its entire simulation context? That is, does
+ * this root not have any parent scapes?
+ */
+ public boolean isRoot() {
+ return scape == null;
+ }
+
+ /**
+ * Has a view update been requested for this cell?
+ */
+ public boolean isUpdateNeeded() {
+ return isUpdateNeeded(getIterationsPerRedraw());
+ }
+
+ /**
+ * Contructs the basic scape structure. Instantiates the agents, but does not
+ * populate them. It is not neccesary to set extent before initializing a
+ * collection, unless you want to have a populated vecotr to begin with.
+ */
+ public void construct() {
+ space.construct();
+ if (getSpace() instanceof Discrete && getPrototypeAgent() == null) {
+ setPrototypeAgent(new Cell());
+ }
+ }
+
+ /**
+ * Populates the scape with clones of the prototype agent. Prototype agent
+ * should be set before calling this method.
+ */
+ public void populate() {
+ space.populate();
+ }
+
+ /**
+ * Create this scape; contruct it, populate it, add rules, create statistic
+ * collectors, etc. Called automatically at model construction, unless
+ * isAutoCreate is set to false. By default, automatically populates all
+ * members with clones of the prototype agent. Of course, this behavior can be
+ * overridden or embellished. To turn off the populate behavior, set populate
+ * on create to false.
+ *
+ * @see #setPopulateOnCreate
+ */
+ public void createScape() {
+ // We use Scape as a prototype simply because Scape is abstract and so
+ // can't be
+ // instantiated. Any scape will do, since we won't be cloning it to
+ // populate.
+ if (isRoot()) {
+ if (getPrototypeAgent() == null) {
+ setPrototypeAgent(new Scape());
+ }
+ if (getRunner() == null) {
+ new NonGraphicRunner().setRootScape(this);
+ }
+ }
+ construct();
+ if (isPopulateOnCreate()) {
+ populate();
+ }
+ }
+
+ /**
+ * Initializes the state of the scape. This is the appropriate place to put
+ * any initialization that is dependent on the state of other ascape objects.
+ * If autoCreate is true, calls createScape() on the scape. Note that for root
+ * scapes, autoCreate is always false. Objects are initialized in the order
+ * they are added to parent scapes.
+ */
+ public void initialize() {
+ if (isRoot()) {
+ setAutoCreate(false);
+ }
+ if (isAutoCreate()) {
+ createScape();
+ }
+ super.initialize();
+ getSpace().initialize();
+ if (!(getSpace() instanceof Continuous) && getPrototypeAgent() != null && getPrototypeAgent().getScape() == this && !getSpace().isMutable()) {
+ executeOnMembers(Cell.CALCULATE_NEIGHBORS_RULE);
+ }
+ }
+
+ /**
+ * Returns current count of iterations.
+ */
+ public final int getIteration() {
+ return getRunner().getIteration();
+ }
+
+ /**
+ * Returns the current period, which is just the iteration plus the period
+ * begin.
+ */
+ public final int getPeriod() {
+ return getRunner().getPeriod();
+ }
+
+ /**
+ * Returns the name that periods are referred to by.
+ */
+ public String getPeriodName() {
+ return getRunner().getPeriodName();
+ }
+
+ /**
+ * Returns a string description of the current period, i.e. "Iteration 1",
+ * "Year 1900", "StarDate 3465.29."
+ */
+ public String getPeriodDescription() {
+ return getPeriodName() + " " + Integer.toString(getPeriod());
+ }
+
+ /**
+ * Sets the name that periods are referred to by.
+ */
+ public void setPeriodName(String name) {
+ getRunner().setPeriodName(name);
+ }
+
+ /**
+ * Adds a rule to this scape, automatically selecting it.
+ */
+ public synchronized void addRule(Rule rule) {
+ addRule(rule, true);
+ }
+
+ /**
+ * Adds a rule to this scape. Allows setting whether rule be should be
+ * selected (run) automatically? If the selection is not changed, rules are
+ * executed in the order they are added.
+ *
+ * @param rule
+ * the rule to add
+ * @param select
+ * if rule should be run false if rule should just be made available
+ * to be run
+ */
+ public synchronized void addRule(Rule rule, boolean select) {
+ if (rule instanceof ExecuteThenUpdate && getExecutionOrder() != RULE_ORDER) {
+ // bug mtp: need to add similar check when setting rule order.
+ throw new RuntimeException("Tried to add execute and update rule to AGENT_ORDER Scape. Set Scape to RULE_ORDER execution first.");
+ }
+ if (rule.getScape() == null) {
+ rule.setScape(this);
+ }
+ rules.addElement(rule, select);
+ }
+
+ /**
+ * Returns all rules that this scape might execute.
+ */
+ public VectorSelection getRules() {
+ return rules;
+ }
+
+ /**
+ * Adds a rule to be executed once following initialization. Rule is
+ * automatically selected for running.
+ *
+ * @param rule
+ * to be executed at simulation start
+ */
+ public synchronized void addInitialRule(Rule rule) {
+ addInitialRule(rule, true);
+ }
+
+ /**
+ * Adds a rule to be executed once following initialization. If the selection
+ * is not chagned, rules are executed in the order they are added.
+ *
+ * @param rule
+ * to be executed at simulation start
+ * @param select
+ * if rule should be run false if rule should just be made available
+ * to be run
+ */
+ public synchronized void addInitialRule(Rule rule, boolean select) {
+ if (rule.getScape() == null) {
+ rule.setScape(this);
+ }
+ initialRules.addElement(rule, select);
+ }
+
+ /**
+ * Returns all the rules executed following scape initialization.
+ */
+ public VectorSelection getInitialRules() {
+ return initialRules;
+ }
+
+ public void setInitialRules(VectorSelection initialRules) {
+ this.initialRules = initialRules;
+ }
+
+ /**
+ * Adds a view to this scape. Takes care of basic housekeeping, including
+ * registering view as listener, and creating window for view to be displayed
+ * within.
+ *
+ * @param view
+ * ComponentView to display in window
+ */
+ public synchronized void addView(ScapeListener view) {
+ this.addView(view, true);
+ }
+
+ /**
+ * Adds a view to this scape. Takes care of basic housekeeping, including
+ * registering view as listener, and creating window for view to be displayed
+ * within. This version of the method allow the adding of a view without
+ * regard to the GUI setting. This method might be useful for instace when
+ * temporaily instrumenting a non-gui run with diagnostics. Normally
+ * addScapeListener should be used.
+ *
+ * @param view
+ * ComponentView to display in window
+ * @param createFrame
+ * should the view be placed within a new window frame?
+ * @param forceGUI
+ * add a GUI view witout regard to the display GUI setting
+ */
+ public synchronized void addView(final ScapeListener view, boolean createFrame, boolean forceGUI) {
+ if (forceGUI || Runner.isDisplayGraphics() || !view.isGraphic() || Runner.isServeGraphics()) {
+ try {
+ this.addScapeListener(view);
+ // if (view instanceof Component) {
+ // // try {
+ // SwingUtilities.invokeLater(new Runnable() {
+ // public void run() {
+ // view.scapeNotification(new ScapeEvent(Scape.this,
+ // ScapeEvent.REPORT_ADDED));
+ // }
+ // });
+ // // } catch (InterruptedException e) {
+ // // e.printStackTrace();
+ // // } catch (InvocationTargetException e) {
+ // // e.printStackTrace();
+ // // }
+ // } else {
+ view.scapeAdded(new ScapeEvent(this, ScapeEvent.REPORT_ADDED));
+ // }
+ } catch (TooManyListenersException e) {
+ throw new RuntimeException("Tried to add a view to more than one scape:\n" + e);
+ }
+ if (createFrame && view.isGraphic()) {
+ if (!Runner.isServeGraphics()) {
+ getEnvironment().addView(view);
+ }
+ // topdo remove view dependency
+ }
+ } else {
+ }
+ }
+
+ /**
+ * Adds a view to this scape. Takes care of basic housekeeping, including
+ * registering view as listener, and creating window for view to be displayed
+ * within. An important exception occurs when a GUI view is added and display
+ * GUI is set to false. In this case, the view will _not_ be added. This makes
+ * it easy to add views in many model components without worrying about
+ * checking for GUI display state. Views can be added regardless of the value
+ * of display GUI by using addViewForce. Note: Even with the conveneince of
+ * this method, it is often nec
+ *
+ * @param view
+ * ComponentView to display in window
+ * @param createFrame
+ * should the view be placed within a new window frame?
+ */
+ public synchronized void addView(ScapeListener view, boolean createFrame) {
+ addView(view, createFrame, false);
+ }
+
+ /**
+ * Adds a view to this scape. Takes care of basic housekeeping, including
+ * registering view as listener, and creating window for view to be displayed
+ * within.
+ *
+ * @param views
+ * ComponentView to display in window
+ */
+ public synchronized void addViews(ScapeListener[] views) {
+ this.addViews(views, true);
+ }
+
+ /**
+ * Adds an array of views to this scape. Takes care of basic housekeeping,
+ * including registering the views as listeners, and creating window for view
+ * to be displayed within. This version of the method allow the adding of a
+ * view without regard to the GUI setting. This method might be useful for
+ * instace when temporaily instrumenting a non-gui run with diagnostics.
+ * Normally addScapeListener should be used.
+ *
+ * @param views
+ * ComponentViews array to display in window
+ * @param createFrame
+ * should the view be placed within a new window frame?
+ * @param forceGUI
+ * add a GUI view witout regard to the dispaly GUI setting
+ */
+ public synchronized void addViews(ScapeListener[] views, boolean createFrame, boolean forceGUI) {
+ if (forceGUI || Runner.isDisplayGraphics() || !views[0].isGraphic()) {
+ try {
+ for (int i = 0; i < views.length; i++) {
+ this.addScapeListener(views[i]);
+ views[i].scapeAdded(new ScapeEvent(this, ScapeEvent.REPORT_ADDED));
+ }
+ } catch (TooManyListenersException e) {
+ throw new RuntimeException("Tried to add a view to more than one scape");
+ }
+ boolean allGraphic = false;
+ for (int i = 0; i < views.length; i++) {
+ if (views[i].isGraphic()) {
+ allGraphic = true;
+ } else {
+ allGraphic = false;
+ break;
+ }
+ }
+ // For now, we're going to assume that if one of the views is
+ // graphic, they all are
+ if (createFrame && allGraphic) {
+ getEnvironment().addViews(views);
+ }
+ }
+ }
+
+ /**
+ * Adds an array of views to this scape. Takes care of basic housekeeping,
+ * including registering the views as listeners, and creating window for view
+ * to be displayed within. An important exception occurs when GUI views are
+ * added and display GUI is set to false. In this case, the views will _not_
+ * be added. This makes it easy to add views in many model components without
+ * worrying about checking for GUI display state. Views can be added
+ * regardless of the value of dispaly GUI by using addViewForce.
+ *
+ * @param views
+ * ComponentViews to display in window
+ * @param createFrame
+ * should the view be placed within a new window frame?
+ */
+ public synchronized void addViews(ScapeListener[] views, boolean createFrame) {
+ // To do, test and throw error for case where user tries to add mixed
+ // gui and non gui views, or the view array is empty
+ addViews(views, createFrame, false);
+ }
+
+ /**
+ * Adds an observer to this scape. This observer will be notified when the
+ * scape has finished iterating, and is expected to notify this scape when it
+ * has updated itself. This method also adds the scape to the listener as a
+ * control listener.
+ *
+ * @param listener
+ * the listern to add
+ */
+ public synchronized void addScapeListener(ScapeListener listener) {
+ if (listener == null) {
+ throw new RuntimeException("Tried to add a null listener to Scape.");
+ }
+ // Not sure if we want to make this poilicy or not..
+ /*
+ * if (listener.getScape() == null) { throw new RuntimeException("Listener
+ * must have this scape assigned before calling addScapeListener."); }
+ */
+ // change to array copy
+ scapeListeners.add(listener);
+ updatedListeners++;
+ listenerOrMemberUpdated();
+ }
+
+ /**
+ * Adds an observer to this scape. This version simple adds the new listener
+ * to the beginning of the list. This can be useful if there are listeners
+ * that need to be called first.
+ *
+ * @param listener
+ * the listern to add
+ */
+ public synchronized void addScapeListenerFirst(ScapeListener listener) {
+ if (listener == null) {
+ throw new RuntimeException("Tried to add a null listener to Scape.");
+ }
+ scapeListeners.add(0, listener);
+ updatedListeners++;
+ listenerOrMemberUpdated();
+ }
+
+ /**
+ * Returns true if and only if the argument is an observer of this scape.
+ */
+ public boolean isScapeListener(ScapeListener listener) {
+ return scapeListeners.contains(listener);
+ }
+
+ /**
+ * Removes the observer from this scape. This observer will be notified when
+ * the scape has finished iterating, and is expected to notify this scape when
+ * it has updated itself.
+ */
+ public synchronized void removeScapeListener(ScapeListener listener) {
+ boolean success = scapeListeners.remove(listener);
+ if (!success) {
+ getEnvironment().getConsole().println("WARNING: Tried to remove unregistered scape listener " + listener + " from scape " + this + ".");
+ }
+
+ listener.scapeRemoved(new ScapeEvent(this, ScapeEvent.REPORT_REMOVED));
+ // we may have just removed the last non-updated listener,
+ // so that everything needing an update has been updated; we need to
+ // check.
+ listenerOrMemberUpdated();
+ }
+
+ /**
+ * Returns all listeners for this scape.
+ */
+ public ArrayList getScapeListeners() {
+ return scapeListeners;
+ }
+
+ // todo (Tried using thread notification, but too slow...perhpas w/
+ // pooling??
+ // class NotificationThread extends Thread {
+ // private ScapeListener listener;
+ // private int id;
+ //
+ // public NotificationThread(ScapeListener listener, int id) {
+ // super(Scape.this + " Scape Notify " + listener);
+ // this.listener = listener;
+ // this.id = id;
+ // }
+ //
+ // public void run() {
+ // listener.scapeNotification(new ScapeEvent(Scape.this, id));
+ // }
+ // }
+
+ /**
+ * Notifies all scape listeners that this scapes state has changed. The root
+ * scape thread then waits until all listeners have been updated.
+ */
+ public void notifyListeners(final int id) {
+ notifyListeners(new ScapeEvent(Scape.this, id));
+ }
+
+ /**
+ * Notifies all scape listeners that this scapes state has changed. The root
+ * scape thread then waits until all listeners have been updated.
+ */
+ public void notifyListeners(final ScapeEvent event) {
+ listenersAndMembersCurrent = false;
+ updatedListeners = 0;
+ updatedMembers = 0;
+ if (scapeListeners.size() > 0) {
+ ArrayList<ScapeListener> currentListeners = (ArrayList) scapeListeners.clone();
+ for (ScapeListener listener : currentListeners) {
+ getRunner().notify(event, listener);
+ }
+ } else {
+ listenerOrMemberUpdated();
+ }
+ }
+
+ /**
+ * Have all views and views of memebers of this scape been updated? [The
+ * grammer is terrible, but it fits the text pattern!]
+ *
+ * @return boolean true if no views are still updating, false if not
+ */
+ public final boolean isAllViewsUpdated() {
+ return listenersAndMembersCurrent;
+ }
+
+ /**
+ * Called whenever a listener or member scape of this scape has been updated.
+ * If all listeners and members have been updated, informs parent scape.
+ */
+ protected synchronized void listenerOrMemberUpdated() {
+ // For testing updating..
+ // if ((updatedListeners >= scapeListeners.length) &&
+ // ((!(getPrototypeAgent() instanceof Scape)) || (!(((Scape)
+ // getPrototypeAgent()).isMembersActive())) || (!(getPrototypeAgent()
+ // instanceof AgentScape)) || (updatedMembers >= getSize()))) {
+ if (updatedListeners >= scapeListeners.size() && (updatedMembers >= getSize() || !(getPrototypeAgent() instanceof Scape) || getSpace() instanceof Singleton || !((Scape) getPrototypeAgent()).isMembersActive())) {
+ listenersAndMembersCurrent = true;
+ updatedListeners = 0;
+ updatedMembers = 0;
+ if (scape != null) {
+ scape.memberUpdated(this);
+ // if (isInitialized() ) {
+ // getRuntimeEnvironment().getConsole().println(scape.
+ // updatedListeners
+ // + "/" +
+ // scape.scapeListeners.length + ", " + scape.updatedMembers +
+ // "/"+scape.getSize() + " for " + scape + " from " + this);
+ // }
+ }
+ }
+ }
+
+ /**
+ * Called whenever a listener has been updated.
+ *
+ * @param listener
+ * the listener tha has been updated
+ */
+ public synchronized void listenerUpdated(ScapeListener listener) {
+ updatedListeners++;
+ // Useful for testing updating problems.
+ // getRuntimeEnvironment().getConsole().println("L " + listener + ": " +
+ // updatedListeners +" of "+ scapeListeners.size()+" ---
+ // "+updatedMembers + " of
+ // " + getSize());
+ listenerOrMemberUpdated();
+ }
+
+ /**
+ * Called whenever a member has been updated.
+ *
+ * @param member
+ * the member that has been updated
+ */
+ public synchronized void memberUpdated(Scape member) {
+ updatedMembers++;
+ // Useful for testing updating problems.
+ // getRuntimeEnvironment().getConsole().println("M " + member + ": " +
+ // updatedListeners +" of "+ scapeListeners.size()+" ---
+ // "+updatedMembers + " of
+ // " + getSize());
+ listenerOrMemberUpdated();
+ }
+
+ /**
+ * Responds to any control events fired at this scape. Currently reacts to
+ * start, stop, pause, resume, step, quit, and restart events, as well as
+ * listener update report events. All control events except listener updates
+ * are passed up to the root. Any other events trigger an untrapped exception.
+ */
+ public void respondControl(ControlEvent control) {
+ if (control.getID() == ControlEvent.REPORT_LISTENER_UPDATED) {
+ listenerUpdated((ScapeListener) control.getSource());
+ } else {
+ getRunner().respondControl(control);
+ }
+ }
+
+ /**
+ * This is for grid communication of changes in draw feature.
+ *
+ * @param event
+ */
+ public void respondDrawFeature(DrawFeatureEvent event) {
+ throw new RuntimeException("The client or worker scape should define their own version of this!");
+ }
+
+ /**
+ * Sets the running state for all scapes. Safe to call on any scape in the
+ * model; the request is propogated to the parent scape. If true, starts the
+ * parent scape's thread, which causes scape to iterate. If set false, the
+ * scape will be stopped when the current iteration is complete.
+ *
+ * @param running
+ * if true, starts the thread, if false, stops it.
+ */
+ public void setRunning(boolean running) {
+ getRunner().setRunning(running);
+ }
+
+ /**
+ * Has the scape been requested to run? <i>Note:</i> if false, indicates that
+ * a stop has been requested, not neccesarily that it has occured, as the
+ * simulation continues the current iteration. If you need to know when a
+ * scape has actually stopped, listen for the scapeStopped event.
+ *
+ * @return the current requested running state
+ */
+ public boolean isRunning() {
+ return getRunner() != null && getRunner().isRunning();
+ }
+
+ /**
+ * Sets the paused state for all parent and member scapes. Safe to call on any
+ * scape in the model; the request is propogated up to the parent scape. If
+ * set true, a pause will occur when the current iteration is complete.
+ *
+ * @param pause
+ * if true, pauses, otherwise resumes iterations
+ */
+ public void setPaused(boolean pause) {
+ if (pause) {
+ getRunner().pause();
+ } else {
+ getRunner().resume();
+ }
+ }
+
+ /**
+ * Has the scape been requested to pause? <i>Note:</i> indicates that a pause
+ * has been requested, not neccesarily that the simulation is paused; it may
+ * be completing its current iteration.
+ *
+ * @return true if pause requested, false if resume requested or running
+ * normally
+ */
+ public boolean isPaused() {
+ return getRunner().isPaused();
+ }
+
+ /**
+ * Sets the earliest period this scape is expected to be run at. 0 by default.
+ *
+ * @param earliestPeriod
+ * the lowest period value this scape can have
+ */
+ public void setEarliestPeriod(int earliestPeriod) {
+ getRunner().setEarliestPeriod(earliestPeriod);
+ }
+
+ /**
+ * Sets the latest period this scape is expected to be run at. Max of integer
+ * (effectively unlimited) by default.
+ *
+ * @param latestPeriod
+ * the highest period value this scape can have
+ */
+ public void setLatestPeriod(int latestPeriod) {
+ getRunner().setLatestPeriod(latestPeriod);
+ }
+
+ /**
+ * Is the supplied period a valid period for this scape?
+ *
+ * @param period
+ * the period to test
+ * @return true if within earliest and latest periods, false otherwise
+ */
+ public boolean isValidPeriod(int period) {
+ return getRunner().isValidPeriod(period);
+ }
+
+ /**
+ * Returns the period this scape begins running at. By default, the greater of
+ * earliest period and 0.
+ */
+ public int getStartPeriod() {
+ return getRunner().getStartPeriod();
+ }
+
+ /**
+ * Sets the start period for this scape. The start period is the period this
+ * scape is given when a model run is started.
+ *
+ * @param startPeriod
+ * the period to begin runs at
+ */
+ public void setStartPeriod(int startPeriod) throws SpatialTemporalException {
+ getRunner().setStartPeriod(startPeriod);
+ }
+
+ /**
+ * Returns the period this scape stops running at. By default, the lesser of
+ * latest period and integer maximum value (effectively unlimited.)
+ */
+ public int getStopPeriod() {
+ return getRunner().getStopPeriod();
+ }
+
+ /**
+ * Sets the stop period for this scape. The stop period is the period that the
+ * scape is automatically stopped at. The scape may be automatically set to
+ * start agina at start value is the scape is set to restart.
+ *
+ * @param stopPeriod
+ * the period the scape will stop at upon reaching
+ * @see #setAutoRestart
+ */
+ public void setStopPeriod(int stopPeriod) throws SpatialTemporalException {
+ getRunner().setStopPeriod(stopPeriod);
+ }
+
+ /**
+ * Returns the period to pause on.
+ */
+ public int getPausePeriod() {
+ return getRunner().getPausePeriod();
+ }
+
+ /**
+ * Causes the model to pause at the specified period.
+ *
+ * @param pausePeriod
+ * when to pause
+ */
+ public void setPausePeriod(int pausePeriod) {
+ getRunner().setPausePeriod(pausePeriod);
+ }
+
+ /**
+ * Does the scape automatically start upon opening? True by default.
+ */
+ public boolean isStartOnOpen() {
+ return Runner.isStartOnOpen();
+ }
+
+ /**
+ * Should the scape be automatically started upon opening? True by default.
+ *
+ * @param startOnOpen
+ * true to start the scape upon opening a model
+ */
+ public void setStartOnOpen(boolean startOnOpen) {
+ Runner.setStartOnOpen(startOnOpen);
+ }
+
+ /**
+ * Should the scape be automatically restarted upon stopping at its stop
+ * period? Setting this value to true allows easy cycling of models for
+ * demonstrations, model explorations, etc. See DataOutputView for an example
+ * of more sophisticated handling of multiple runs.
+ *
+ * @param autoRestart
+ * true to restart the scape upon reaching stop period, false to
+ * simple stop
+ * @see #setStopPeriod
+ */
+ public void setAutoRestart(boolean autoRestart) {
+ getRunner().setAutoRestart(autoRestart);
+ }
+
+ /**
+ * Returns the root of this scape, which may be this scape. This was an older
+ * usage and is retained for backward compatability only. It is now not a all
+ * good name as it confuses model for a view / control component, and may be
+ * removed in the future.
+ *
+ * @deprecated please use #getRunner().
+ */
+ public Runner getModel() {
+ return getRunner();
+ }
+
+ /**
+ * Returns the runtime model environment, which manages model-wide state such
+ * as run status.
+ *
+ * @return the model environment for entire model
+ */
+ public Runner getRunner() {
+ return getRoot().runner;
+ }
+
+ public void setRunner(Runner _runner) {
+ runner = _runner;
+ }
+
+ /**
+ * Returns the path in which all files should by default be stored to and
+ * retrieved from. Nonstatic, so that parameter can automatically be set from
+ * command line, but backing variable is static. Default is "./", can be
+ * modified by calling setHome or providing an ascape.home java property.
+ * (This may change now since it is no longer neccesary.)
+ */
+ public String getHome() {
+ return getRunner().getHome();
+ }
+
+ /**
+ * Sets the path in which to store all scape related files. Nonstatic, so that
+ * parameter can automatically be set from command line, but backing variable
+ * is static.
+ *
+ * @param home
+ * the fully qualified path name for this scape
+ */
+ public void setHome(String home) {
+ getRunner().setHome(home);
+ }
+
+ /**
+ * Are members of this active scape model participants, that is, do they have
+ * rules executed upon them? Default is true.
+ *
+ * @return true if members actively execute rules, false otherwise
+ */
+ public boolean isMembersActive() {
+ return membersActive;
+ }
+
+ /**
+ * Sets whether members of this scape actively execute rules upon members.
+ *
+ * @param membersActive
+ * true if members actively execute rules, false otherwise
+ */
+ public void setMembersActive(boolean membersActive) {
+ this.membersActive = membersActive;
+ }
+
+ /**
+ * Do cells request view updates manually or are all cells automatically
+ * updated every view cycle? While requiring cells to request updates manually
+ * adds a little to complication to model design and maintenance, manual
+ * requests allow a significant boost in view performance, as all cells do not
+ * have to be drawn every cycle. False by default.
+ *
+ * @return true if cells must request updates, false if cell updates handled
+ * automatically
+ */
+ public boolean isCellsRequestUpdates() {
+ return cellsRequestUpdates;
+ }
+
+ /**
+ * Should cells request view updates manually or are all cells automatically
+ * updated every view cycle? See above. <i>Important:</i> If you set this
+ * value to be true, you are responsible for ensuring that the
+ * <code>requestUpdate</code> method is called anytime a cell's state changes
+ * such that a view may be affected. Some of these calls will be handled for
+ * you automatically, for instance, it is not neccesary to call requestUpdate
+ * when a cell moves, since the HostCell calls requestUpdates for you.
+ * Typically, you will need to request updates when the internal state of a
+ * cell changes and that is reflected in how a cell is represeneted in a view,
+ * for example, if you color an agent for wealth, you will need to call
+ * <code>requestUpdate</code> anytime the agent wealth changes.
+ *
+ * @param cellsRequestUpdates
+ * if cells should request updates, false if cell updates should be
+ * handled automatically
+ * @see Cell#requestUpdate
+ */
+ public void setCellsRequestUpdates(boolean cellsRequestUpdates) {
+ this.cellsRequestUpdates = cellsRequestUpdates;
+ }
+
+ /**
+ * Executes the provided rules on the supplied agentArray.
+ */
+ public void execute(List rules, List agents) {
+ Agent[] agentArray = new Agent[agents.size()];
+ agents.toArray(agentArray);
+ int[] order = CollectionSpace.createOrder(agentArray.length);
+ if (executionOrder == AGENT_ORDER) {
+ order = CollectionSpace.randomizeOrder(order, getRandom());
+ for (int i = 0; i < agentArray.length; i++) {
+ for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
+ Rule rule = (Rule) iterator.next();
+ rule.execute(agentArray[order[i]]);
+ }
+ }
+ } else { // executionOrder == RULE_ORDER
+ // Add call so that cells can respond even if this is not the
+ // primary agent
+ for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
+ Rule rule = (Rule) iterator.next();
+
+ if (rule.isRandomExecution()) {
+ order = CollectionSpace.randomizeOrder(order, getRandom());
+ }
+ for (int i = 0; i < agentArray.length; i++) {
+ rule.execute(agentArray[order[i]]);
+ }
+ if (rule instanceof ExecuteThenUpdate) {
+ if (rule.isRandomExecution()) {
+ order = CollectionSpace.randomizeOrder(order, getRandom());
+ }
+ for (int i = 0; i < agentArray.length; i++) {
+ ((ExecuteThenUpdate) rule).update(agentArray[order[i]]);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Executes the provided rule on every member of the lattice, according to the
+ * rule settings and the execution order of this scape.
+ */
+ public void execute(Rule rule, List agents) {
+ List rules = new ArrayList(1);
+ rules.add(rule);
+ execute(rules, agents);
+ }
+
+ /**
+ * Executes all of this scapes selected rules on its members.
+ */
+ public void executeOnMembers() {
+ executeOnMembers(rules);
+ }
+
+ /**
+ * Executes the provided rules on every member of the lattice, according to
+ * the rule settings and the execution order of this scape.
+ */
+ public void executeOnMembers(VectorSelection ruleSelection) {
+ executeOnMembers(ruleSelection.getSelection());
+ }
+
+ /**
+ * Executes the provided rule on every member of the lattice, according to the
+ * rule settings and the execution order of this scape.
+ */
+ public void executeOnMembers(Rule rule) {
+ Rule[] rules = new Rule[1];
+ rules[0] = rule;
+ executeOnMembers(rules);
+ }
+
+ /**
+ * Executes the provided rules on every member of the collection, according to
+ * the rule settings and the execution order of the scape.
+ */
+ public void executeOnMembers(Object[] rules) {
+ if (rules.length > 0) {
+ strategy = new StrategyFactory(this, rules, Scape.threadCount).getStrategy();
+ strategy.execute();
+ }
+ }
+
+ /**
+ * Returns an iterator across all agents in this scape. Note that this is
+ * simply an iterator of the backing collections members. It will have
+ * different behavior than is typically desried when iterating behavior across
+ * a scape*; so for instance, this method is not used by the internal rule
+ * mechanism. It should be perfectly adequete for tight iterations across
+ * agents when there are no additions or deletions during the iteration; for
+ * instance, when calcualting some value across a number of agents. *The
+ * iterator will not be aware of an agents deletion from the scape after its
+ * creation; this is because the scape caches these removals to improve
+ * performance. It may include agents that are added to the scape after its
+ * creation, and this is typically not desirable behavior when touring a
+ * collection of current agents.
+ *
+ * @return an iterator over the agents in scape order
+ */
+ public Iterator iterator() {
+ return space.iterator();
+ }
+
+ /**
+ * Propogates the rule for execution up to the root of the scape tree, then
+ * propogates down to all nodes.
+ */
+ public void executeOnRoot(Rule[] rules) {
+ if (scape == null) {
+ // Top level, so execute for all nodes
+ execute(rules);
+ } else {
+ // Still have parent scapes, so propogate up
+ scape.executeOnRoot(rules);
+ }
+ }
+
+ /**
+ * Propogates the rule for execution up to the root of the scape tree, then
+ * propogates down to all nodes.
+ */
+ public void executeOnRoot(Rule rule) {
+ Rule[] rules = new Rule[1];
+ rules[0] = rule;
+ executeOnRoot(rules);
+ }
+
+ /**
+ * Holds the current search rule. Make non-static to make searching
+ * threadsafe.
+ */
+ private static SearchRule defaultSearch;
+
+ /**
+ * Searches through the scape for an object (agent) that matches the supplied
+ * key and comparator. Typically will return the first agent found, but this
+ * behavior is not guranteed. For now, this is implemented as a simple linear
+ * search, so search time is O(n). Future versions may allow use of a binary
+ * search where the scape is allready appropriatly sorted, or may allow a
+ * cached comparator map to be used. For now if the scape is sorted in an
+ * order matching the comparators order, you can use "getAsList" and
+ * Collections.binarySearch to get an O(log(n)) search. This code is not
+ * thread safe, but can easily be made so.
+ *
+ * @param comparator
+ * the Comparator to use to perfrom the search
+ * @param key
+ * the key that an agent must match in order to be returned.
+ */
+ public Agent search(Comparator comparator, Object key) {
+ if (defaultSearch == null) {
+ defaultSearch = new SearchRule("Default Scape Search Rule");
+ }
+ defaultSearch.setComparator(comparator);
+ defaultSearch.setKey(key);
+ defaultSearch.setSearchType(SearchRule.SEARCH_EQUAL);
+ defaultSearch.clear();
+ executeOnMembers(defaultSearch);
+ return defaultSearch.getFoundAgent();
+ }
+
+ /**
+ * Searches through the scape for an object (agent) that has the minimum value
+ * as defined by the comparator.
+ *
+ * @param comparator
+ * the Comparator to use to determin the minimum
+ */
+ public Agent searchMin(Comparator comparator) {
+ if (defaultSearch == null) {
+ defaultSearch = new SearchRule("Default Scape Search Rule");
+ }
+ defaultSearch.setComparator(comparator);
+ defaultSearch.setSearchType(SearchRule.SEARCH_MIN);
+ defaultSearch.clear();
+ executeOnMembers(defaultSearch);
+ return defaultSearch.getFoundAgent();
+ }
+
+ /**
+ * Searches through the scape for an object (agent) that has the minimum value
+ * as defined by the comparator.
+ *
+ * @param comparator
+ * the Comparator to use to determin the minimum
+ */
+ public Agent searchMax(Comparator comparator) {
+ if (defaultSearch == null) {
+ defaultSearch = new SearchRule("Default Scape Search Rule");
+ }
+ defaultSearch.setComparator(comparator);
+ defaultSearch.setSearchType(SearchRule.SEARCH_MAX);
+ defaultSearch.clear();
+ executeOnMembers(defaultSearch);
+ return defaultSearch.getFoundAgent();
+ }
+
+ /**
+ * If true, turns on value (typically for statistics) collection, else turns
+ * off stat collection.
+ */
+ public void setCollectStats(boolean collect) {
+ if (collect) {
+ collectStats = new CollectStats();
+ collectStats.setScape(this);
+ } else {
+ collectStats = null;
+ }
+ }
+
+ /**
+ * Returns the value collection rule in effect; null if no value collection.
+ */
+ public CollectStats getCollectStats() {
+ return collectStats;
+ }
+
+ /**
+ * Sets the value collection rule to the one supplied. Allows use of custom
+ * value collection rules. Please let me know if you use this..considering
+ * removal.
+ */
+ public void setCollectStats(CollectStats collectStats) {
+ this.collectStats = collectStats;
+ collectStats.setScape(this);
+ }
+
+ /**
+ * Is the scape responsible for creating itself and its members, or are other
+ * classes responsible for creating the scape? If true (default) calls the
+ * createScape method on model construction, typically causing the scape to be
+ * populated with clones of prototype agent. If false, scape must be populated
+ * manually.
+ */
+ public boolean isAutoCreate() {
+ return autoCreate;
+ }
+
+ /**
+ * Sets wether the scape is responsible for creating itself and its members,
+ * or other model components handle this.
+ *
+ * @param autoCreate
+ * if true calls createScape at construction, otherwise model is
+ * built manually
+ */
+ public void setAutoCreate(boolean autoCreate) {
+ this.autoCreate = autoCreate;
+ }
+
+ /**
+ * Is the scape populated when the scape is created? That is, is the populate
+ * scape method called when create scape is executed? (Typically, the populate
+ * scape method will fill each cell with clones of the prototype cell, but of
+ * course this behavior can be overidden.) True by default.
+ *
+ * @return true if the scape will be populated when scape create is called,
+ * false otherwise
+ */
+ public boolean isPopulateOnCreate() {
+ return populateOnCreate;
+ }
+
+ /**
+ * Sets wether the scape is responsible for populating itself.
+ *
+ * @param populateOnCreate
+ * if true calls createScape at construction, otherwise model is
+ * built manually
+ */
+ public void setPopulateOnCreate(boolean populateOnCreate) {
+ this.populateOnCreate = populateOnCreate;
+ }
+
+ /**
+ * Adds the specified stat collectors to this scape for automatic collection
+ * by the scape. If this scape is not allready collecting stats, implicitly
+ * sets collect stats to true. Adds the stats to the stat collection rule.
+ *
+ * @param stats
+ * the stat collectors to add to this scape.
+ */
+ public void addStatCollectors(StatCollector[] stats) {
+ // stats added in collect values
+ // getData().addStatCollectors(StatCollectors);
+
+ // loop through and give the stats references for their datagroup.
+ // must be done prior to getData().add(stats), because
+ // DataGroup.add(Stats)
+ // calls getAllDataSeries, which calls isCollectingLongitudinal, which
+ // uses the StatCollector's
+ // reference to its data group.
+ for (int i = 0; i < stats.length; i++) {
+ stats[i].setDataGroup(getRunner().getData());
+ }
+ getRunner().getData().add(stats);
+ if (collectStats == null) {
+ setCollectStats(true);
+ }
+ collectStats.addStatCollectors(stats);
+ }
+
+ /**
+ * Adds the specified stat collector iff and only if it hasn't allready been
+ * added.
+ *
+ * @param stat
+ * the stat collector to add to this scape. todo allow replacement
+ * (cuurent version only adds if a stat does not already exist.)
+ * possibly get rid of this once issue with multiple stat collectors
+ * is resolved.
+ */
+ public StatCollector addStatCollectorIfNew(StatCollector stat) {
+ StatCollector foundStat = getRunner().getData().getStatCollector(stat.getName());
+ if (foundStat == null) {
+ addStatCollector(stat);
+ foundStat = stat;
+ }
+ return foundStat;
+ }
+
+ /**
+ * Adds the specified stat collector to this scape for automatic collection by
+ * the scape. If this scape is not allready collecting stats, implicitly sets
+ * collect stats to true. Adds the stat to the stat collection rule.
+ *
+ * @param stat
+ * the stat collector to add to this scape.
+ */
+ public void addStatCollector(StatCollector stat) {
+ StatCollector[] stats = new StatCollector[1];
+ stats[0] = stat;
+ addStatCollectors(stats);
+ }
+
+ /**
+ * Returns the stat collectors currently calcualting stats for this scape.
+ */
+ public StatCollector[] getStatCollectors() {
+ if (collectStats != null) {
+ return collectStats.getStatCollectors();
+ } else {
+ throw new RuntimeException("Tried to get stats but they are not being collected");
+ }
+ }
+
+ /**
+ * Just a class for a delegated proxy for draw features.
+ */
+ public class DrawFeatureObservable extends Observable implements Serializable {
+
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- /**
- * Have to provide this silly method because set changed is protected
- * for some reason.
- */
- public void setChanged() {
- super.setChanged();
- }
- };
-
- /**
- * A delegate keeping track of observers of draw features.
- */
- private DrawFeatureObservable drawFeatureObservable = new DrawFeatureObservable();
-
- /**
- * Adds the provided draw feature to this scape.
- *
- * @see org.ascape.util.vis.awt.DrawFeature
- */
- public void addDrawFeature(PlatformDrawFeature feature) {
- // Simple linear search...
- // todo, replace with hashmap mechanism
- for (Iterator iterator = drawFeatures.iterator(); iterator.hasNext();) {
- PlatformDrawFeature drawFeature = (PlatformDrawFeature) iterator.next();
- if (drawFeature.getName().equals(feature.getName())) {
- // ignore, don't add feature with same name twice.
- return;
- }
- }
- drawFeatures.addElement(feature);
- drawFeatureObservable.setChanged();
- drawFeatureObservable.notifyObservers();
- }
-
- /**
- * Removes the provided draw feature.
- *
- * @param feature the draw feature to be removed
- * @return returns true if successful. False, otherwise.
- */
- public boolean removeDrawFeature(PlatformDrawFeature feature) {
- PlatformDrawFeature found = null;
- // todo, replace with hashmap mechanism
- for (Iterator iterator = drawFeatures.iterator(); iterator.hasNext();) {
- PlatformDrawFeature drawFeature = (PlatformDrawFeature) iterator.next();
- if (drawFeature.getName().equals(feature.getName())) {
- found = feature;
- }
- }
- if (found != null) {
- drawFeatures.removeElement(found);
- drawFeatureObservable.setChanged();
- drawFeatureObservable.notifyObservers();
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Returns an observable delegate that notifies users of draw features that
- * a change has occurred. If you need to know when a change in draw features
- * occur, implement observer in the appropriate class and add it to the
- * Observerable this method returns.
- */
- public Observable getDrawFeaturesObservable() {
- return drawFeatureObservable;
- }
-
- /**
- * Returns, as a vector, the draw features available for interpretation of
- * members of this scape.
- *
- * @see org.ascape.util.vis.awt.DrawFeature
- */
- public Vector getDrawFeatures() {
- return drawFeatures;
- }
-
- /**
- * Returns the user environment for this scape. Returns null if no user
- * environmnet exists; that is if we are running in a non graphic context.
- * Otherwise, returns the same environmnet as getRuntimeEnvironment, except
- * cast apprpriatly.
- */
- public AbstractUIEnvironment getUIEnvironment() {
- if (getRunner() != null && getRunner().getEnvironment() instanceof AbstractUIEnvironment) {
- return (AbstractUIEnvironment) getRunner().getEnvironment();
- } else {
- return null;
- }
- }
-
- /**
- * Returns the runtime environment, if any, for this scape.
- */
- public RuntimeEnvironment getEnvironment() {
- return getRunner() != null ? getRunner().getEnvironment() : null;
- }
-
- /**
- * A class defining a rule causing the target scape to return all accessors.
- */
- class RetrieveAccessorsRule extends Rule {
-
- /**
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Have to provide this silly method because set changed is protected for
+ * some reason.
+ */
+ public void setChanged() {
+ super.setChanged();
+ }
+ };
+
+ /**
+ * A delegate keeping track of observers of draw features.
+ */
+ private DrawFeatureObservable drawFeatureObservable = new DrawFeatureObservable();
+
+ /**
+ * Adds the provided draw feature to this scape.
+ *
+ * @see org.ascape.util.vis.awt.DrawFeature
+ */
+ public void addDrawFeature(PlatformDrawFeature feature) {
+ // Simple linear search...
+ // todo, replace with hashmap mechanism
+ for (Iterator iterator = drawFeatures.iterator(); iterator.hasNext();) {
+ PlatformDrawFeature drawFeature = (PlatformDrawFeature) iterator.next();
+ if (drawFeature.getName().equals(feature.getName())) {
+ // ignore, don't add feature with same name twice.
+ return;
+ }
+ }
+ drawFeatures.addElement(feature);
+ drawFeatureObservable.setChanged();
+ drawFeatureObservable.notifyObservers();
+ }
+
+ /**
+ * Removes the provided draw feature.
+ *
+ * @param feature
+ * the draw feature to be removed
+ * @return returns true if successful. False, otherwise.
+ */
+ public boolean removeDrawFeature(PlatformDrawFeature feature) {
+ PlatformDrawFeature found = null;
+ // todo, replace with hashmap mechanism
+ for (Iterator iterator = drawFeatures.iterator(); iterator.hasNext();) {
+ PlatformDrawFeature drawFeature = (PlatformDrawFeature) iterator.next();
+ if (drawFeature.getName().equals(feature.getName())) {
+ found = feature;
+ }
+ }
+ if (found != null) {
+ drawFeatures.removeElement(found);
+ drawFeatureObservable.setChanged();
+ drawFeatureObservable.notifyObservers();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns an observable delegate that notifies users of draw features that a
+ * change has occurred. If you need to know when a change in draw features
+ * occur, implement observer in the appropriate class and add it to the
+ * Observerable this method returns.
+ */
+ public Observable getDrawFeaturesObservable() {
+ return drawFeatureObservable;
+ }
+
+ /**
+ * Returns, as a vector, the draw features available for interpretation of
+ * members of this scape.
+ *
+ * @see org.ascape.util.vis.awt.DrawFeature
+ */
+ public Vector getDrawFeatures() {
+ return drawFeatures;
+ }
+
+ /**
+ * Returns the user environment for this scape. Returns null if no user
+ * environmnet exists; that is if we are running in a non graphic context.
+ * Otherwise, returns the same environmnet as getRuntimeEnvironment, except
+ * cast apprpriatly.
+ */
+ public AbstractUIEnvironment getUIEnvironment() {
+ if (getRunner() != null && getRunner().getEnvironment() instanceof AbstractUIEnvironment) {
+ return (AbstractUIEnvironment) getRunner().getEnvironment();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the runtime environment, if any, for this scape.
+ */
+ public RuntimeEnvironment getEnvironment() {
+ return getRunner() != null ? getRunner().getEnvironment() : null;
+ }
+
+ /**
+ * A class defining a rule causing the target scape to return all accessors.
+ */
+ class RetrieveAccessorsRule extends Rule {
+
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- List accessors;
-
- public RetrieveAccessorsRule() {
- super("Retrieve Accessors Rule");
- }
-
- /**
- * @param agent the target scape
- */
- public void execute(Agent agent) {
- try {
- accessors.addAll(PropertyAccessor.determineReadWriteAccessors(this, Scape.class, false));
- } catch (IntrospectionException e) {
- getEnvironment().getConsole().println(
- "An introspection exception occured while trying to determine model properties: "
- + e.getMessage());
- }
- }
- }
-
- /**
- * A class defining a rule causing the target scape to search for all scapes
- * and members scapes accessors.
- */
- // class RetrieveAllAccessorsRule extends PropogateScapeOnly {
- class RetrieveAllAccessorsRule extends Rule {
-
- /**
+ private static final long serialVersionUID = 1L;
+
+ List accessors;
+
+ public RetrieveAccessorsRule() {
+ super("Retrieve Accessors Rule");
+ }
+
+ /**
+ * @param agent
+ * the target scape
+ */
+ public void execute(Agent agent) {
+ try {
+ accessors.addAll(PropertyAccessor.determineReadWriteAccessors(this, Scape.class, false));
+ } catch (IntrospectionException e) {
+ getEnvironment().getConsole().println("An introspection exception occured while trying to determine model properties: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * A class defining a rule causing the target scape to search for all scapes
+ * and members scapes accessors.
+ */
+ // class RetrieveAllAccessorsRule extends PropogateScapeOnly {
+ class RetrieveAllAccessorsRule extends Rule {
+
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- List accessors;
-
- public RetrieveAllAccessorsRule() {
- super("Retrieve Accessors Rule");
- accessors = new ArrayList();
- }
-
- /**
- * @param agent the target scape
- */
- public void execute(Agent agent) {
- if (((Scape) agent).isMembersActive()) {
- try {
- accessors.addAll(PropertyAccessor.determineReadWriteAccessors(agent, Scape.class, false));
- } catch (IntrospectionException e) {
- getEnvironment().getConsole().println(
- "An introspection exception occured while trying to determine model properties: "
- + e.getMessage());
- }
- // super.execute(agent);
- }
- }
- }
-
- /**
- * A class defining a rule causing the target scape to search for all scapes
- * and members scapes accessors.
- */
- class RetrieveAllScapesRule extends PropogateScapeOnly {
-
- /**
+ private static final long serialVersionUID = 1L;
+
+ List accessors;
+
+ public RetrieveAllAccessorsRule() {
+ super("Retrieve Accessors Rule");
+ accessors = new ArrayList();
+ }
+
+ /**
+ * @param agent
+ * the target scape
+ */
+ public void execute(Agent agent) {
+ if (((Scape) agent).isMembersActive()) {
+ try {
+ accessors.addAll(PropertyAccessor.determineReadWriteAccessors(agent, Scape.class, false));
+ } catch (IntrospectionException e) {
+ getEnvironment().getConsole().println("An introspection exception occured while trying to determine model properties: " + e.getMessage());
+ }
+ // super.execute(agent);
+ }
+ }
+ }
+
+ /**
+ * A class defining a rule causing the target scape to search for all scapes
+ * and members scapes accessors.
+ */
+ class RetrieveAllScapesRule extends PropogateScapeOnly {
+
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- Vector scapes;
-
- public RetrieveAllScapesRule() {
- super("Retrieve Scapes Rule");
- scapes = new Vector();
- }
-
- /**
- * @param agent the target scape
- */
- public void execute(Agent agent) {
- scapes.addElement(agent);
- super.execute(agent);
- }
- }
-
- /**
- * Returns all property accessors for this scape and recursivly for all
- * member scapes of this scape.
- */
- private List retrieveAllAccessorsBase() {
- RetrieveAllAccessorsRule retrieveRule = new RetrieveAllAccessorsRule();
- executeOnRoot(retrieveRule);
- retrieveRule.accessors.add(new PropertyAccessor(this, "RandomSeed"));
- retrieveRule.accessors.add(new PropertyAccessor(this, "StartPeriod"));
- retrieveRule.accessors.add(new PropertyAccessor(this, "StopPeriod"));
- retrieveRule.accessors.add(new PropertyAccessor(this, "PausePeriod"));
- retrieveRule.accessors.add(new PropertyAccessor(this, "ThreadCount"));
- return retrieveRule.accessors;
- }
-
- /**
- * Returns all property accessors for this scape and recursivly for all
- * member scapes of this scape.
- */
- public List retrieveAllAccessors() {
- List accessors = retrieveAllAccessorsBase();
- return accessors;
- }
-
- public final static Comparator COMPARE_ORDERED_QUALIFIERS = new Comparator() {
- public int compare(Object o1, Object o2) {
- return Utility.orderedQualifiers(((PropertyAccessor) o1).getLongName()).compareTo(
- Utility.orderedQualifiers(((PropertyAccessor) o2).getLongName()));
- }
- };
-
- /**
- * Returns all property accessors for this scape and recursivly for all
- * member scapes of this scape.
- */
- public List retrieveAllAccessorsOrdered() {
- List accessors = retrieveAllAccessorsBase();
- Collections.sort(accessors, COMPARE_ORDERED_QUALIFIERS);
- return accessors;
- }
-
- /**
- * Returns all property accessors for this scape (excluding
- * inappropriate/disabled accessors such as size) and recursivly for all
- * member scapes of this scape. Can be overriden to only include those
- * accessors that should be included in model definitions.
- */
- public List retrieveModelAccessorsOrdered() {
- List accessors = retrieveAllAccessorsOrdered();
- for (Iterator iterator = accessors.iterator(); iterator.hasNext();) {
- PropertyAccessor accessor = (PropertyAccessor) iterator.next();
- if (accessor.getName().equalsIgnoreCase("size")) {
- iterator.remove();
- }
- }
- return accessors;
- }
-
- /**
- * Returns all scapes that are composed with this scape. All subscapes,
- * parent scapes, and subscapes of parent scapes (more simply, the root
- * scape and all of its subscapes) are returned.
- */
- public List getAllScapes() {
- RetrieveAllScapesRule retrieveRule = new RetrieveAllScapesRule();
- executeOnRoot(retrieveRule);
- return retrieveRule.scapes;
- }
-
- /**
- * Does the scape view itself? True by default for root scape when
- * createViews is used, false otherwise.
- */
- public boolean isViewSelf() {
- return selfView != null;
- }
-
- /**
- * Sets wether the scape is a view of itself. True by default for root scape
- * whn createViews is used, false otherwise. Not extensively tested yet.
- *
- * @param viewSelf should the scape view itself.
- */
- public void setViewSelf(boolean viewSelf) {
- if (viewSelf && !isViewSelf()) {
- createSelfView();
- } else if (!viewSelf && isViewSelf()) {
- removeScapeListener(selfView);
- }
- }
-
- /**
- * Makes the scape a view of itself.
- */
- public void createSelfView() {
- selfView = new ScapeListenerDelegate(this) {
- /**
+ private static final long serialVersionUID = 1L;
+
+ Vector scapes;
+
+ public RetrieveAllScapesRule() {
+ super("Retrieve Scapes Rule");
+ scapes = new Vector();
+ }
+
+ /**
+ * @param agent
+ * the target scape
+ */
+ public void execute(Agent agent) {
+ scapes.addElement(agent);
+ super.execute(agent);
+ }
+ }
+
+ /**
+ * Returns all property accessors for this scape and recursivly for all member
+ * scapes of this scape.
+ */
+ private List retrieveAllAccessorsBase() {
+ RetrieveAllAccessorsRule retrieveRule = new RetrieveAllAccessorsRule();
+ executeOnRoot(retrieveRule);
+ retrieveRule.accessors.add(new PropertyAccessor(this, "RandomSeed"));
+ retrieveRule.accessors.add(new PropertyAccessor(this, "StartPeriod"));
+ retrieveRule.accessors.add(new PropertyAccessor(this, "StopPeriod"));
+ retrieveRule.accessors.add(new PropertyAccessor(this, "PausePeriod"));
+ retrieveRule.accessors.add(new PropertyAccessor(this, "ThreadCount"));
+ return retrieveRule.accessors;
+ }
+
+ /**
+ * Returns all property accessors for this scape and recursivly for all member
+ * scapes of this scape.
+ */
+ public List retrieveAllAccessors() {
+ List accessors = retrieveAllAccessorsBase();
+ return accessors;
+ }
+
+ public final static Comparator COMPARE_ORDERED_QUALIFIERS = new Comparator() {
+ public int compare(Object o1, Object o2) {
+ return Utility.orderedQualifiers(((PropertyAccessor) o1).getLongName()).compareTo(Utility.orderedQualifiers(((PropertyAccessor) o2).getLongName()));
+ }
+ };
+
+ /**
+ * Returns all property accessors for this scape and recursivly for all member
+ * scapes of this scape.
+ */
+ public List retrieveAllAccessorsOrdered() {
+ List accessors = retrieveAllAccessorsBase();
+ Collections.sort(accessors, COMPARE_ORDERED_QUALIFIERS);
+ return accessors;
+ }
+
+ /**
+ * Returns all property accessors for this scape (excluding
+ * inappropriate/disabled accessors such as size) and recursivly for all
+ * member scapes of this scape. Can be overriden to only include those
+ * accessors that should be included in model definitions.
+ */
+ public List retrieveModelAccessorsOrdered() {
+ List accessors = retrieveAllAccessorsOrdered();
+ for (Iterator iterator = accessors.iterator(); iterator.hasNext();) {
+ PropertyAccessor accessor = (PropertyAccessor) iterator.next();
+ if (accessor.getName().equalsIgnoreCase("size")) {
+ iterator.remove();
+ }
+ }
+ return accessors;
+ }
+
+ /**
+ * Returns all scapes that are composed with this scape. All subscapes, parent
+ * scapes, and subscapes of parent scapes (more simply, the root scape and all
+ * of its subscapes) are returned.
+ */
+ public List getAllScapes() {
+ RetrieveAllScapesRule retrieveRule = new RetrieveAllScapesRule();
+ executeOnRoot(retrieveRule);
+ return retrieveRule.scapes;
+ }
+
+ /**
+ * Does the scape view itself? True by default for root scape when createViews
+ * is used, false otherwise.
+ */
+ public boolean isViewSelf() {
+ return selfView != null;
+ }
+
+ /**
+ * Sets wether the scape is a view of itself. True by default for root scape
+ * whn createViews is used, false otherwise. Not extensively tested yet.
+ *
+ * @param viewSelf
+ * should the scape view itself.
+ */
+ public void setViewSelf(boolean viewSelf) {
+ if (viewSelf && !isViewSelf()) {
+ createSelfView();
+ } else if (!viewSelf && isViewSelf()) {
+ removeScapeListener(selfView);
+ }
+ }
+
+ /**
+ * Makes the scape a view of itself.
+ */
+ public void createSelfView() {
+ selfView = new ScapeListenerDelegate(this) {
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- public String getName() {
- return this + " Self-View";
- }
- };
- addView(selfView);
- }
-
- /**
- * Constructs the views for this scape. If display graphics is set to true,
- * calls create graphic views. Calls create nongraphic views in either case.
- * Override to create views for the scape. Alternativly, override the
- * createGraphicsViews and createNonGraphicViews methods to create views
- * appropriate for the current operating mode. This method does NOT get
- * called when a model is deserialized, but createGraphicViews does.
- */
- public void createViews() {
- if (isRoot() && getRunner().getEnvironment() == null) {
- getRunner().createEnvironment();
- addView(getRunner().getEnvironment());
- }
- createNonGraphicViews();
- if (Runner.isDisplayGraphics() || Runner.isServeGraphics()) {
- // SwingUtilities.invokeLater(new Runnable() {
- // public void run() {
- createGraphicViews();
- // }
- // });
- }
- }
-
- /**
- * Override to create any graphical views for the scape. This method will
- * not be called when display graphics is set to false, and so is a good
- * place to put any user interface only views. If root, will setup the user
- * interface environment and add an auto customizer.
- */
- public void createGraphicViews() {
- }
-
- /**
- * Overide to create and non-graphical views for the scape. If root, will
- * automatically create control and counter views, create a self view, add a
- * standand output view.
- */
- public void createNonGraphicViews() {
- if (isRoot()) {
- createSelfView();
- getEnvironment().getConsole().println("Ascape Model: " + getName());
- getEnvironment().getConsole().println(getDescription());
- }
- }
-
- /*
- * public PropertyAccessor[] retrieveAccessors(PropertyAccessor[] accessors)
- * throws IntrospectionException { return
- * retrieveAccessors(PropertyAccessor.determineAccessors(this,
- * Model.class)); }
- */
-
- /**
- * If the scape has delegated a view to itself, called each time a scape
- * sends a "initialize" event, indicating it has been initialized. Normally
- * wouldn't use in this context.
- */
- public void scapeInitialized(ScapeEvent scapeEvent) {
- }
-
- /**
- * If the scape has delegated a view to itself, called each time a scape
- * sends a "setup" method, indicating it needs to be setup for a run.
- * Possible uses include setting initial vector extents, responding to
- * changes in user settings, and changing parameters systematically. (A view
- * delegate to the scape is automatically created for root scapes when the
- * standard model implementation is used.)
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeSetup(ScapeEvent scapeEvent) {
- }
-
- /**
- * If the scape has delegated a view to itself, called each time the scape
- * is iterated. (A view delegate to the scape is automatically created for
- * root scapes when the standard model implementation is used.)
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeIterated(ScapeEvent scapeEvent) {
- }
-
- /**
- * If the scape has delegated a view to itself, called each time the scape
- * is started. (A view delegate to the scape is automatically created for
- * root scapes when the standard model implementation is used.)
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeStarted(ScapeEvent scapeEvent) {
- }
-
- /**
- * If the scape has delegated a view to itself, called each time the scape
- * is stopped. (A view delegate to the scape is automatically created for
- * root scapes when the standard model implementation is used.)
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeStopped(ScapeEvent scapeEvent) {
- }
-
- /**
- * If the scape has delegated a view to itself, called each time the scape
- * is updated. (A view delegate to the scape is automatically created for
- * root scapes when the standard model implementation is used.)
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeNotification(ScapeEvent scapeEvent) {
- }
-
- /**
- * If the scape has delegated a view to itself, called each time a scape
- * sends a "closing" event. Normally wouldn't use in this context.
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeClosing(ScapeEvent scapeEvent) {
- }
-
- /**
- * Method called as the entire envornmnet is about to be exited.
- *
- * @param scapeEvent the associated scape event
- */
- public void environmentQuiting(ScapeEvent scapeEvent) {
- }
-
- /**
- * If the scape has delegated a view to itself, called each time a scape
- * sends a "deserialized" event.
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeDeserialized(ScapeEvent scapeEvent) {
- if (Runner.isDisplayGraphics()) {
- if (isRoot()) {
- getRunner().createEnvironment();
- addView(getRunner().getEnvironment());
- }
- }
- }
-
- /**
- * Add a scape to this listener. Just here to fulfill the scape listener
- * contract.
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeAdded(ScapeEvent scapeEvent) throws TooManyListenersException {
- }
-
- /**
- * Notifies the listener that the scape has removed it. Just here to fulfill
- * the scape listener contract.
- *
- * @param scapeEvent the associated scape event
- */
- public void scapeRemoved(ScapeEvent scapeEvent) {
- }
-
- /**
- * Returns false the scape is not a graphical user interface component.
- */
- public boolean isGraphic() {
- return false;
- }
-
- /**
- * Returns true (default) if the listener is intended to be used only for
- * the current scape; certainly true in this case.
- */
- public boolean isLifeOfScape() {
- return true;
- }
-
- /*
- * Returns the ascape home directory. public static String getAscapeHome() {
- * //return System.getProperty("ascape.home", "D:/"); return ""; }
- */
-
- /**
- * Save the state of the scape to a file.
- */
- public void save(File file) throws IOException {
- OutputStream os = new FileOutputStream(file);
- save(os);
- }
-
- /**
- * Save the state of the scape to an output stream.
- */
- public void save(OutputStream os) throws IOException {
- if (!isSerializable()) {
- throw new RuntimeException("Tried to save a model that is not serializable.");
- }
-
- getRunner().setInternalRunning(false);
-
- GZIPOutputStream gzos = new GZIPOutputStream(os);
- ObjectOutputStream oos = new ObjectOutputStream(gzos);
-
- // remove the customizer and any environment (non-scape specific) views
- boolean needToAddCustomizer = false;
- if (getUIEnvironment() != null && getUIEnvironment().getCustomizer() != null
- && isScapeListener(getUIEnvironment().getCustomizer())) {
- removeScapeListener(getUIEnvironment().getCustomizer());
- needToAddCustomizer = true;
- }
- for (int i = 0; i < getEnvironment().getEnvironmentViews().size(); i++) {
- ScapeListener l = (ScapeListener) getEnvironment().getEnvironmentViews().get(i);
- l.getScape().removeScapeListener(l);
- }
-
- try {
- oos.writeObject(this);
- } catch (StackOverflowError e) {
- e.printStackTrace();
- System.err.println("");
- System.err.println("************************************");
- throw new RuntimeException("PLEASE INCREASE STACK SIZE, e.g. by using java's -Xss command line paramter.");
- }
- oos.close();
-
- // reconnect the customizer and any environment (non-scape specific)
- // views
- if (needToAddCustomizer) {
- addScapeListener(getUIEnvironment().getCustomizer());
- }
- for (int i = 0; i < getEnvironment().getEnvironmentViews().size(); i++) {
- ScapeListener l = (ScapeListener) getEnvironment().getEnvironmentViews().get(i);
- addView(l, false);
- }
-
- // we set startPeriod to scape.period + 1 so that there is not a blank
- // first point in the charts
- try {
- setStartPeriod(getPeriod() + 1);
- } catch (SpatialTemporalException e) {
- try {
- setStartPeriod(getPeriod());
- } catch (SpatialTemporalException e1) {
- try {
- setStartPeriod(getPeriod());
- } catch (SpatialTemporalException e2) {
- throw new RuntimeException("Internal Error");
- }
- }
- }
- getRunner().setInternalRunning(true);
- }
-
- private void writeObject(final java.io.ObjectOutputStream out) throws IOException {
-
- if (getRunner().getData() != null) {
- getRunner().getData().getPeriods().clear();
- }
-
- getRunner().write(out);
- }
-
- /**
- * Sets values for the models paramters based on supplied array of key value
- * pairs. Paramters and values are expected to be seperated with an "=", for
- * example: "MyParameter=12".
- *
- * @param args an array of strings with paramter-value paris in the form
- * "{paramter-name}={paramter-value}"
- * @param reportNotFound if paramters not found should result in a console
- * notification and if errors in invocation should be reported,
- * false otherwise
- */
- public void assignParameters(String[] args, boolean reportNotFound) {
- // List allAccessors = retrieveAllAccessors();
- List allAccessors = null;
- try {
- allAccessors = PropertyAccessor.determineReadWriteAccessors(this, Scape.class, false);
- } catch (IntrospectionException e) {
- throw new RuntimeException(e);
- }
-
- for (String arg : args) {
- String paramName = PropertyAccessor.paramName(arg);
- if (paramName != null) {
- boolean found = false;
- String paramValue = PropertyAccessor.paramValue(arg);
- for (Iterator iterator = allAccessors.iterator(); iterator.hasNext();) {
- PropertyAccessor accessor = (PropertyAccessor) iterator.next();
- if (accessor.getName().equalsIgnoreCase(paramName)) {
- try {
- accessor.setAsText(paramValue);
- } catch (InvocationTargetException e) {
- if (reportNotFound) {
- throw new RuntimeException("Exception in called method: " + e.getTargetException());
- }
- // Else ignore, its ok if there is a problem calling
- // the method at this point
- }
- found = true;
- }
- }
-
- found = found || Runner.assignEnvironmentParameter(paramName, paramValue);
- if (!found) {
- if (paramName.equalsIgnoreCase("RandomSeed")) {
- try {
- setRandomSeed(PropertyAccessor.paramValueLong(arg));
- } catch (NumberFormatException e) {
- getEnvironment().getConsole().println("Couldn't decode random seed value: " + paramValue);
- }
- found = true;
- } else if (paramName.equalsIgnoreCase("StopPeriod")) {
- try {
- setStopPeriod(PropertyAccessor.paramValueInt(arg));
- found = true;
- } catch (SpatialTemporalException e) {
- e.printStackTrace(); // To change body of catch
- // statement use File | Settings
- // | File Templates.
- }
- } else if (paramName.equalsIgnoreCase("PausePeriod")) {
- setPausePeriod(PropertyAccessor.paramValueInt(arg));
- found = true;
- } else if (paramName.equalsIgnoreCase("AutoRestart")) {
- setAutoRestart(PropertyAccessor.paramValueBoolean(arg));
- found = true;
- }
- }
- if (!found && reportNotFound) {
- getEnvironment().getConsole().println(
- "***WARNING: Parameter not found: " + paramName + " in " + getName());
- }
- }
- }
- }
-
- public void createViews(String[] args) {
- if (args != null) {
- for (String arg : args) {
- if (PropertyAccessor.paramName(arg).equals("view")) {
- ScapeListener newView =
- (ScapeListener) getRunner().instanceFromName(PropertyAccessor.paramValue(arg));
- if (newView != null) {
- addView(newView);
- }
- }
- }
- }
- }
-
- /**
- * Sets values for the models paramters based on supplied array of key value
- * pairs, reporting if any of the keys (parameter names) are not found.
- * Paramters and values are expected to be seperated with an "=", for
- * example: "MyParameter=12".
- *
- * @param args an array of strings with paramter-value paris in the form
- * "{paramter-name}={paramter-value}"
- */
- public void assignParameters(String[] args) {
- assignParameters(args, true);
- }
-
- /**
- * Moves an agent toward the specified agent.
- *
- * @param origin the agent moving
- * @param target the agent's target
- * @param distance the distance to move
- */
- public final void moveAway(LocatedAgent origin, Coordinate target, double distance) {
- getSpace().moveAway(origin, target, distance);
- }
-
- /**
- * Moves an agent toward the specified agent. It is an error to call this
- * method on collections (and discrete discrete scapes not composed of
- * HostCells.
- *
- * @param origin the agent moving
- * @param target the agent's target
- * @param distance the distance to move
- */
- public final void moveToward(LocatedAgent origin, Coordinate target, double distance) {
- getSpace().moveToward(origin, target, distance);
- }
-
- /**
- * Returns the shortest distance between one agent and another.
- *
- * @param origin the starting agent
- * @param target the ending agent
- */
- public double calculateDistance(LocatedAgent origin, LocatedAgent target) {
- return calculateDistance(origin.getCoordinate(), target.getCoordinate());
- }
-
- /**
- * Returns the shortest distance between one LocatedAgent and another.
- * Warning: this default method only returns a coordinate specific distance.
- * It uses no information about the scape context; for example wether it is
- * a periodic (wrapping) space or not. Therefore, if you implement your own
- * versions of Scape, ensure that you have properly implemented a version of
- * this method. (All Ascape Scape collections properly overide this method.)
- *
- * @param origin one LocatedAgent
- * @param target another LocatedAgent
- */
- public final double calculateDistance(Coordinate origin, Coordinate target) {
- return getSpace().calculateDistance(origin, target);
- }
-
- public class ConditionalIterator implements Iterator {
-
- Iterator iter;
-
- Conditional condition;
-
- Object next;
-
- public ConditionalIterator(Iterator iter, Conditional condition) {
- ConditionalIterator.this.iter = iter;
- ConditionalIterator.this.condition = condition;
- loadNext();
- }
-
- private void loadNext() {
- next = null;
- while (iter.hasNext() && next == null) {
- Object o = iter.next();
- if (condition.meetsCondition(o)) {
- next = o;
- }
- }
- }
-
- public boolean hasNext() {
- return next != null;
- }
-
- public Object next() {
- if (next != null) {
- Object currentNext = next;
- loadNext();
- return currentNext;
- } else {
- throw new NoSuchElementException();
- }
- }
-
- public void remove() {
- throw new UnsupportedOperationException("Can't remove from a conditional iterator.");
- }
- }
-
- /**
- * Find the maximum cell of some data point. If multiple points have the
- * same value, returns a random instance at that value.
- *
- * @param condition
- * @return
- */
- public final List find(Conditional condition) {
- return space.find(condition);
- }
-
- /**
- * Find the maximum cell of some data point. If multiple points have the
- * same value, returns a random instance at that value.
- *
- * @param iter
- * @param dataPoint
- * @return
- */
- public final LocatedAgent findMaximum(final Iterator iter, DataPoint dataPoint) {
- // The code is written in such a way that there will not be the cost of
- // Array creation if only one maximum exists
- ArrayList multipleMaxObjects = null;
- double maxValue = -Double.MAX_VALUE;
- LocatedAgent maxObject = null;
- while (iter.hasNext()) {
- Object next = iter.next();
- if (dataPoint.getValue(next) > maxValue) {
- maxValue = dataPoint.getValue(next);
- maxObject = (LocatedAgent) next;
- multipleMaxObjects = null;
- }
- // Awaiting decision to become depndent on 1.4
- // else if (Double.compare(dataPoint.getValue(next), maxValue) == 0)
- // {
- else if (DataPointConcrete.equals(dataPoint.getValue(next), maxValue)) {
- if (multipleMaxObjects == null) {
- multipleMaxObjects = new ArrayList();
- multipleMaxObjects.add(maxObject);
- }
- multipleMaxObjects.add(next);
- }
- }
- if (multipleMaxObjects == null) {
- return maxObject;
- } else {
- return (LocatedAgent) multipleMaxObjects.get(randomToLimit(multipleMaxObjects.size()));
- }
- }
-
- public final LocatedAgent findMinimumWithin(Coordinate coordinate, DataPoint dataPoint, Conditional condition,
- boolean includeSelf, double distance) {
- return (LocatedAgent) getSpace().findMinimumWithin(coordinate, dataPoint, condition, includeSelf, distance);
- }
-
- public final LocatedAgent findMaximumWithin(Coordinate coordinate, DataPoint dataPoint, Conditional condition,
- boolean includeSelf, double distance) {
- return (LocatedAgent) getSpace().findMaximumWithin(coordinate, dataPoint, condition, includeSelf, distance);
- }
-
- public final LocatedAgent findMinimum(final Iterator iter, DataPoint dataPoint) {
- // The code is written in such a way that there will not be the cost of
- // Array creation if only one minimum exists
- ArrayList multipleMinObjects = null;
- double minValue = Double.MAX_VALUE;
- LocatedAgent minObject = null;
- while (iter.hasNext()) {
- Object next = iter.next();
- if (dataPoint.getValue(next) < minValue) {
- minValue = dataPoint.getValue(next);
- minObject = (LocatedAgent) next;
- multipleMinObjects = null;
- }
- // Awaiting decision to become depndent on 1.4
- // else if (Double.compare(dataPoint.getValue(next), minValue) == 0)
- // {
- else if (DataPointConcrete.equals(dataPoint.getValue(next), minValue)) {
- if (multipleMinObjects == null) {
- multipleMinObjects = new ArrayList();
- multipleMinObjects.add(minObject);
- }
- multipleMinObjects.add(next);
- }
- }
- if (multipleMinObjects == null) {
- return minObject;
- } else {
- return (LocatedAgent) multipleMinObjects.get(randomToLimit(multipleMinObjects.size()));
- }
- }
-
- /**
- * Returns an iteration across all agents the specified distance from the
- * origin.
- *
- * @param origin the starting cell
- * @param includeSelf should the origin be included
- * @param distance the distance agents must be within to be included
- */
- public final Iterator withinIterator(final Coordinate origin, Conditional condition, boolean includeSelf,
- final double distance) {
- return getSpace().withinIterator(origin, condition, includeSelf, distance);
- }
-
- /**
- * Returns the agent with the minimum value.
- *
- * @param point the data point to use to make the comparison for minimum
- */
- public LocatedAgent findMinimum(DataPoint point) {
- return findMinimum(iterator(), point);
- }
-
- /**
- * Returns the agent with the maximum value.
- *
- * @param point the data point to use to make the comparison for maximum
- */
- public LocatedAgent findMaximum(DataPoint point) {
- return findMaximum(iterator(), point);
- }
-
- /**
- * The strategy that will be used to execute rules across this scape.
- */
- private ExecutionStrategy strategy;
-
- private static int threadCount = 1;
-
- /**
- * Finds the nearest agent that meets some condition. Scapes without
- * coordinate meaing should override this method.
- *
- * @param origin the coordinate to find agents near
- * @param condition the condition that found agent must meet
- * @param includeOrigin if the origin should be included
- * @param distance the maximum distance around the origin to look
- */
- public final LocatedAgent findNearest(final Coordinate origin, Conditional condition, boolean includeOrigin,
- double distance) {
- return (LocatedAgent) getSpace().findNearest(origin, condition, includeOrigin, distance);
- }
-
- /**
- * Returns a coordinate randomly selected from the collection's space.
- */
- public final Coordinate findRandomCoordinate() {
- return getSpace().findRandomCoordinate();
- }
-
- /**
- * Returns all agents within the specified distance of the agent.
- *
- * @param origin the coordinate at the center of the search
- * @param includeSelf whether or not the starting agent should be included
- * in the search
- * @param distance the distance agents must be within to be included
- */
- public final List findWithin(Coordinate origin, Conditional condition, boolean includeSelf, double distance) {
- return getSpace().findWithin(origin, condition, includeSelf, distance);
- }
-
- /**
- * Returns the number of agents within the specified distance of the agent
- * that meet some condition.
- *
- * @param origin the coordinate at the center of the search
- * @param condition the condition the agent must meet to be included
- * @param distance the distance agents must be within to be included
- */
- public final int countWithin(Coordinate origin, Conditional condition, boolean includeSelf, double distance) {
- return getSpace().countWithin(origin, condition, includeSelf, distance);
- }
-
- /**
- * Returns if there are agents within the specified distance of the origin
- * that meet some Condition.
- *
- * @param origin the coordinate at the center of the search
- * @param condition the condition the agent must meet to be included
- * @param distance the distance agents must be within to be included
- */
- public final boolean hasWithin(final Coordinate origin, Conditional condition, boolean includeSelf, double distance) {
- return getSpace().hasWithin(origin, condition, includeSelf, distance);
- }
-
- public final boolean isMutable() {
- return getSpace().isMutable();
- }
-
- /**
- * Returns a string composed of descriptions of the contents.
- */
- public String contentsToString() {
- String contents = "";
- for (Iterator iterator = space.iterator(); iterator.hasNext();) {
- Agent agent = (Agent) iterator.next();
- contents = contents + agent.toString();
- if (iterator.hasNext()) {
- contents = contents + ", ";
- }
- }
- return contents;
- }
-
- /**
- * Returns a string representation of this scape.
- */
- public String toString() {
- if (name != null) {
- return name;
- } else {
- if (isRoot()) {
- return "Root Scape";
- } else if (prototypeAgent != null) {
- return "Scape of " + prototypeAgent.toString() + "(s)";
- } else {
- return "Scape of agents of unspecified type";
- }
- }
- }
-
- public boolean isSerializable() {
- return serializable;
- }
-
- public void setSerializable(boolean serializable) {
- this.serializable = serializable;
- }
-
- /**
- * Overides the clone method to do a deep clone of member state so that such
- * state will not be shared between scapes.
- */
- public Object clone() {
- Scape clone = (Scape) super.clone();
- clone.scapeListeners = new ArrayList();
- for (Iterator iter = scapeListeners.iterator(); iter.hasNext();) {
- ScapeListener thisListener = (ScapeListener) iter.next();
- try {
- ScapeListener newListener = (ScapeListener) thisListener.clone();
- removeScapeListener(newListener);
- newListener.scapeRemoved(new ScapeEvent(this, ScapeEvent.REPORT_REMOVED));
- newListener.scapeAdded(new ScapeEvent(clone, ScapeEvent.REPORT_ADDED));
- clone.addScapeListener(newListener);
- } catch (TooManyListenersException e) {
- throw new RuntimeException("Internal error in Scape.clone " + e);
- }
- }
- if (prototypeAgent != null) {
- clone.prototypeAgent = (Agent) prototypeAgent.clone();
- }
- if (rules != null) {
- clone.rules = (VectorSelection) rules.clone();
- }
- if (initialRules != null) {
- clone.initialRules = (VectorSelection) initialRules.clone();
- }
- clone.drawFeatures = (Vector) drawFeatures.clone();
- clone.space = (CollectionSpace) space.clone();
- return clone;
- }
-
- /**
- * Returns an agent randomly selected from the collection. If no agents
- * exist, returns null.
- */
- public final LocatedAgent findRandom() {
- return (LocatedAgent) getSpace().findRandom();
- }
-
- /**
- * Returns a random unoccupied discrete location in the space given with the
- * lattice.
- *
- * @param excludeAgent a cell to exclude from get (typically origin)
- */
- public Agent findRandom(Location excludeAgent) {
- return (LocatedAgent) getSpace().findRandom(excludeAgent);
- }
-
- /**
- * Returns an agent randomly that matches a condition. Note: If there are no
- * agents in the collection that meet the condition, the method returns
- * null.
- *
- * @param condition the condition that must be matched
- */
- public final Agent findRandom(Conditional condition) {
- return (LocatedAgent) getSpace().findRandom(condition);
- }
-
- /**
- * Creates a new agent in this collection by cloning the prototype agent,
- * adding it in an arbitrary place (typically at the end of a list), and
- * initializing it.
- */
- public synchronized Agent newAgent() {
- return newAgent(false);
- }
-
- /**
- * Creates a new agent in this collection by cloning the prototype agent,
- * adding it to a random or arbitrary (last in most cases) place in the
- * collection, and initializing it.
- *
- * @param randomLocation should the agent be placed in a random location, or
- * in an arbitrary location?
- */
- public synchronized Agent newAgent(boolean randomLocation) {
- Agent newAgent = (LocatedAgent) getSpace().newLocation(randomLocation);
- List agents = new LinkedList();
- agents.add(newAgent);
- execute(getInitialRules().getVector(), agents);
- return newAgent;
- }
-
- /**
- * Returns the number of agents in the scape.
- *
- * @return the number of agents in the scape
- */
- public int size() {
- return getSize();
- }
-
- /**
- * Are there no agents in this scape?
- *
- * @return true if the scape is empty
- */
- public final boolean isEmpty() {
- return getSpace().isEmpty();
- }
-
- /**
- * Returns true if the scape collection contains the object (agent.)
- *
- * @param o the agent to search for
- * @return true if the scape contains the agent
- */
- public final boolean contains(Object o) {
- return getSpace().contains(o);
- }
-
- /**
- * Returns an array containing all of the elements in this collection in
- * proper sequence. Obeys the general contract of the
- * <tt>Collection.toArray</tt> method.
- *
- * @return an array containing all of the elements in this collection in
- * proper sequence.
- * @see java.util.Arrays#asList(java.lang.Object[])
- */
- public final Object[] toArray() {
- return getSpace().toArray();
- }
-
- /**
- * Returns an array containing the current agents in this scape; the runtime
- * type is specified by the passed array.
- *
- * @param a the array to copy the agents to
- * @return an array containing the agents
- * @throws java.lang.ArrayStoreException if the runtime type of the
- * specified array doesn't match all agents
- */
- public final Object[] toArray(Object a[]) {
- return getSpace().toArray(a);
- }
-
- /**
- * Returns true if this collection contains all of agents in the specified
- * collection.
- *
- * @param c collection of agents to be found in the scape
- * @return true if this scape contains all of the agents in the collection
- */
- public final boolean containsAll(Collection c) {
- return getSpace().containsAll(c);
- }
-
- /**
- * Adds all of the agent in the specified collection to the end of the
- * scape. Assumes (but does not check) that all of the elements are
- * instances of agent.
- *
- * @param c collection whose agents are to be added to the scape
- * @return true if the scape had new agents added
- */
- public final boolean addAll(Collection c) {
- return getSpace().addAll(c);
- }
-
- /**
- * Removes all of the agnets contained in the collection. No attempt is made
- * to cache the removal; the agents are all removed at once.
- *
- * @param c collection whose agents are to be added to the scape
- * @return true if the scape had agents (but not neccessarily all?) removed
- */
- public final boolean removeAll(Collection c) {
- return getSpace().removeAll(c);
- }
-
- /**
- * Retains only the elements in the scape that are in the specified
- * collection.
- *
- * @param c collection whose agents are to be retained in the scape
- * @return true if this scape had agents removed
- */
- public final boolean retainAll(Collection c) {
- return getSpace().retainAll(c);
- }
-
- /**
- * Removes all agents from the scape.
- */
- public final void clear() {
- getSpace().clear();
- }
-
- /**
- * Adds the supplied object (agent) to this collection.
- */
- public boolean add(Object a) {
- return add(a, true);
- }
-
- /**
- * Adds the supplied object (assumed to be an agent) to this collection. The
- * object is assumed to be an agent, though that behavior may be loosened at
- * some point.
- *
- * @param agent the agent to add
- * @param isParent should this scape be made the parent scape of the agent?
- * @throws UnsupportedOperationException if this scape's space is not a
- * list.
- */
- public final boolean add(Object agent, boolean isParent) {
- if (!(agent instanceof Agent)) {
- // This may change at some point..
- throw new ClassCastException("Scape collections expect Agents only.");
- }
- boolean success = getSpace().add(agent, isParent);
- if (isParent) {
- ((Agent) agent).setScape(this);
- }
- return success;
- }
-
- /**
- * Adds the supplied object (agent) to this collection.
- *
- * @throws UnsupportedOperationException if this scape's space is not a
- * list.
- */
- public final void add(int index, Object a) {
- add(index, a, true);
- }
-
- /**
- * Adds the supplied object (assumed to be an agent) to this collection. The
- * object is assumed to be an agent, though that behavior may be loosened at
- * some point.
- *
- * @param o the agent to add
- * @param isParent should this scape be made the parent scape of the agent?
- * @throws UnsupportedOperationException if this scape's space is not a
- * list.
- */
- public final void add(int index, Object o, boolean isParent) {
- try {
- ((ListSpace) getSpace()).add(index, o, isParent);
- if (isParent) {
- ((Agent) o).setScape(this);
- }
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
- }
- }
-
- /**
- * Removes the supplied object (agent) from this collection.
- *
- * @param o the agent to be removed
- * @return true if the agent was deleted, false otherwise
- */
- public boolean remove(Object o) {
- return space.remove(o);
- }
-
- /**
- * Removes the object at the index from this collection.
- *
- * @param index the index for the agent to remove
- * @throws UnsupportedOperationException if this scape's space is not a
- * list.
- */
- public final Object remove(int index) {
- try {
- return ((List) getSpace()).remove(index);
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
- }
- }
-
- /**
- * Returns the cell existing at the specified coordinate.
- */
- public final LocatedAgent get(Coordinate coordinate) {
- return (LocatedAgent) getSpace().get(coordinate);
- }
-
- /**
- * Sets the agent at the specified coordinate to the supplied agent.
- *
- * @param coordinate the coordinate to add the agent at
- * @param agent the agent to add
- */
- public final void set(Coordinate coordinate, LocatedAgent agent, boolean isParent) {
- getSpace().set(coordinate, agent);
- if (isParent) {
- agent.setScape(getScape());
- agent.setCoordinate(coordinate);
- }
- }
-
- /**
- * Sets the agent at the specified coordinate to the supplied agent.
- *
- * @param coordinate the coordinate to add the agent at
- * @param agent the agent to add
- */
- public void set(Coordinate coordinate, LocatedAgent agent) {
- set(coordinate, agent, true);
- }
-
- /**
- * Returns the cell existing at the specified location. Convenience method.
- *
- * @throws UnsupportedOperationException if this scape's space is not a
- * list.
- */
- public final Object get(int index) {
- try {
- return ((ListBase) getSpace()).get(index);
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
- }
- }
-
- /**
- * Sets the specified location to the provided agent. Convenience method.
- *
- * @throws UnsupportedOperationException if this scape's space is not a
- * list.
- */
- public void set(int index, Object agent) {
- set(index, agent, true);
- }
-
- /**
- * Sets the specified location to the provided agent. Convenience method.
- *
- * @throws UnsupportedOperationException if this scape's space is not a
- * list.
- */
- public void set(int index, Object agent, boolean isParent) {
- try {
- ((ListBase) getSpace()).set(index, (LocatedAgent) agent, isParent);
- if (isParent) {
- ((Agent) agent).setScape(this);
- }
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
- }
- }
-
- public final ResetableIterator scapeIterator() {
- return getSpace().safeIterator();
- }
-
- public final RandomIterator scapeRandomIterator() {
- return getSpace().safeRandomIterator();
- }
-
- protected final ResetableIterator scapeIterator(int start, int limit) {
- return getSpace().safeIterator(start, limit);
- }
-
- public boolean isPeriodic() {
- return getSpace().isPeriodic();
- }
-
- public void setPeriodic(boolean periodic) {
- getSpace().setPeriodic(periodic);
- }
-
- public Scape getSuperScape() {
- return getSpace() instanceof SubSpace ? (Scape) ((SubSpace) getSpace()).getSuperSpace().getContext() : null;
- }
-
- public void setSuperScape(Scape superScape) {
- try {
- ((SubSpace) getSpace()).setSuperSpace(superScape.getSpace());
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException("Underlying scape is no a SubSpace.");
- }
- }
-
- /**
- * Returns multiple independently thread safe scape iterators across all
- * agents in this scape.
- *
- * @return an iterator over the agents in scape order
- */
- public final ResetableIterator[] scapeIterators(int count) {
- return getSpace().safeIterators(count);
- }
-
- public boolean isListenersAndMembersCurrent() {
- return listenersAndMembersCurrent;
- }
-
- public final Space getSpace() {
- return space;
- }
-
- public void setSpace(Space space) {
- this.space = space;
- // todo remove circular dependency
- space.setContext(this);
- space.setRandom(getRandom());
- }
-
- /**
- * Sets the size of the collection, filling with clones of prototype agent.
- * It is an error to set size while a scape is running.
- *
- * @param size a coordinate describing the size of this scape
- */
- public void setSize(int size) {
- if (runner != null && runner.isRunning()) {
- throw new RuntimeException("Tried to set size while scape was running");
- }
- space.setSize(size);
- }
-
- public int getThreadCount() {
- return Scape.threadCount;
- }
-
- public void setThreadCount(int threadCount) {
- Scape.threadCount = threadCount;
- }
-
- public Location getPrototype() {
- return (Location) getPrototypeAgent();
- }
-
- public boolean isHome(Location a) {
- return ((Agent) a).getScape() == this;
- }
-
- /**
- * Convenience method for obtaining sata for current run.
- *
- * @return the Runner's Data Group.
- */
- public DataGroup getData() {
- return getRunner().getData();
- }
-
- /**
- * Returns the UI Environment.
- *
- * @return a UI environment appropriate for given UI.
- * @deprecated retained for backward compatability, please use
- * #getUIEnvironment instead.
- */
- public AbstractUIEnvironment getUserEnvironment() {
- return getUIEnvironment();
- }
+ private static final long serialVersionUID = 1L;
+
+ public String getName() {
+ return this + " Self-View";
+ }
+ };
+ addView(selfView);
+ }
+
+ /**
+ * Constructs the views for this scape. If display graphics is set to true,
+ * calls create graphic views. Calls create nongraphic views in either case.
+ * Override to create views for the scape. Alternativly, override the
+ * createGraphicsViews and createNonGraphicViews methods to create views
+ * appropriate for the current operating mode. This method does NOT get called
+ * when a model is deserialized, but createGraphicViews does.
+ */
+ public void createViews() {
+ if (isRoot() && getRunner().getEnvironment() == null) {
+ getRunner().createEnvironment();
+ addView(getRunner().getEnvironment());
+ }
+ createNonGraphicViews();
+ if (Runner.isDisplayGraphics() || Runner.isServeGraphics()) {
+ // SwingUtilities.invokeLater(new Runnable() {
+ // public void run() {
+ createGraphicViews();
+ // }
+ // });
+ }
+ }
+
+ /**
+ * Override to create any graphical views for the scape. This method will not
+ * be called when display graphics is set to false, and so is a good place to
+ * put any user interface only views. If root, will setup the user interface
+ * environment and add an auto customizer.
+ */
+ public void createGraphicViews() {
+ }
+
+ /**
+ * Overide to create and non-graphical views for the scape. If root, will
+ * automatically create control and counter views, create a self view, add a
+ * standand output view.
+ */
+ public void createNonGraphicViews() {
+ if (isRoot()) {
+ createSelfView();
+ getEnvironment().getConsole().println("Ascape Model: " + getName());
+ getEnvironment().getConsole().println(getDescription());
+ }
+ }
+
+ /*
+ * public PropertyAccessor[] retrieveAccessors(PropertyAccessor[] accessors)
+ * throws IntrospectionException { return
+ * retrieveAccessors(PropertyAccessor.determineAccessors(this, Model.class));
+ * }
+ */
+
+ /**
+ * If the scape has delegated a view to itself, called each time a scape sends
+ * a "initialize" event, indicating it has been initialized. Normally wouldn't
+ * use in this context.
+ */
+ public void scapeInitialized(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * If the scape has delegated a view to itself, called each time a scape sends
+ * a "setup" method, indicating it needs to be setup for a run. Possible uses
+ * include setting initial vector extents, responding to changes in user
+ * settings, and changing parameters systematically. (A view delegate to the
+ * scape is automatically created for root scapes when the standard model
+ * implementation is used.)
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeSetup(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * If the scape has delegated a view to itself, called each time the scape is
+ * iterated. (A view delegate to the scape is automatically created for root
+ * scapes when the standard model implementation is used.)
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeIterated(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * If the scape has delegated a view to itself, called each time the scape is
+ * started. (A view delegate to the scape is automatically created for root
+ * scapes when the standard model implementation is used.)
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeStarted(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * If the scape has delegated a view to itself, called each time the scape is
+ * stopped. (A view delegate to the scape is automatically created for root
+ * scapes when the standard model implementation is used.)
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeStopped(ScapeEvent scapeEvent) {
+ }
+
+ public void scapePaused(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * If the scape has delegated a view to itself, called each time the scape is
+ * updated. (A view delegate to the scape is automatically created for root
+ * scapes when the standard model implementation is used.)
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeNotification(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * If the scape has delegated a view to itself, called each time a scape sends
+ * a "closing" event. Normally wouldn't use in this context.
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeClosing(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * Method called as the entire envornmnet is about to be exited.
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void environmentQuiting(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * If the scape has delegated a view to itself, called each time a scape sends
+ * a "deserialized" event.
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeDeserialized(ScapeEvent scapeEvent) {
+ if (Runner.isDisplayGraphics()) {
+ if (isRoot()) {
+ getRunner().createEnvironment();
+ addView(getRunner().getEnvironment());
+ }
+ }
+ }
+
+ /**
+ * Add a scape to this listener. Just here to fulfill the scape listener
+ * contract.
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeAdded(ScapeEvent scapeEvent) throws TooManyListenersException {
+ }
+
+ /**
+ * Notifies the listener that the scape has removed it. Just here to fulfill
+ * the scape listener contract.
+ *
+ * @param scapeEvent
+ * the associated scape event
+ */
+ public void scapeRemoved(ScapeEvent scapeEvent) {
+ }
+
+ /**
+ * Returns false the scape is not a graphical user interface component.
+ */
+ public boolean isGraphic() {
+ return false;
+ }
+
+ /**
+ * Returns true (default) if the listener is intended to be used only for the
+ * current scape; certainly true in this case.
+ */
+ public boolean isLifeOfScape() {
+ return true;
+ }
+
+ /*
+ * Returns the ascape home directory. public static String getAscapeHome() {
+ * //return System.getProperty("ascape.home", "D:/"); return ""; }
+ */
+
+ /**
+ * Save the state of the scape to a file.
+ */
+ public void save(File file) throws IOException {
+ OutputStream os = new FileOutputStream(file);
+ save(os);
+ }
+
+ /**
+ * Save the state of the scape to an output stream.
+ */
+ public void save(OutputStream os) throws IOException {
+ if (!isSerializable()) {
+ throw new RuntimeException("Tried to save a model that is not serializable.");
+ }
+
+ getRunner().setInternalRunning(false);
+
+ GZIPOutputStream gzos = new GZIPOutputStream(os);
+ ObjectOutputStream oos = new ObjectOutputStream(gzos);
+
+ // remove the customizer and any environment (non-scape specific) views
+ boolean needToAddCustomizer = false;
+ if (getUIEnvironment() != null && getUIEnvironment().getCustomizer() != null && isScapeListener(getUIEnvironment().getCustomizer())) {
+ removeScapeListener(getUIEnvironment().getCustomizer());
+ needToAddCustomizer = true;
+ }
+ for (int i = 0; i < getEnvironment().getEnvironmentViews().size(); i++) {
+ ScapeListener l = (ScapeListener) getEnvironment().getEnvironmentViews().get(i);
+ l.getScape().removeScapeListener(l);
+ }
+
+ try {
+ oos.writeObject(this);
+ } catch (StackOverflowError e) {
+ e.printStackTrace();
+ System.err.println("");
+ System.err.println("************************************");
+ throw new RuntimeException("PLEASE INCREASE STACK SIZE, e.g. by using java's -Xss command line paramter.");
+ }
+ oos.close();
+
+ // reconnect the customizer and any environment (non-scape specific)
+ // views
+ if (needToAddCustomizer) {
+ addScapeListener(getUIEnvironment().getCustomizer());
+ }
+ for (int i = 0; i < getEnvironment().getEnvironmentViews().size(); i++) {
+ ScapeListener l = (ScapeListener) getEnvironment().getEnvironmentViews().get(i);
+ addView(l, false);
+ }
+
+ // we set startPeriod to scape.period + 1 so that there is not a blank
+ // first point in the charts
+ try {
+ setStartPeriod(getPeriod() + 1);
+ } catch (SpatialTemporalException e) {
+ try {
+ setStartPeriod(getPeriod());
+ } catch (SpatialTemporalException e1) {
+ try {
+ setStartPeriod(getPeriod());
+ } catch (SpatialTemporalException e2) {
+ throw new RuntimeException("Internal Error");
+ }
+ }
+ }
+ getRunner().setInternalRunning(true);
+ }
+
+ private void writeObject(final java.io.ObjectOutputStream out) throws IOException {
+
+ if (getRunner().getData() != null) {
+ getRunner().getData().getPeriods().clear();
+ }
+
+ getRunner().write(out);
+ }
+
+ /**
+ * Sets values for the models paramters based on supplied array of key value
+ * pairs. Paramters and values are expected to be seperated with an "=", for
+ * example: "MyParameter=12".
+ *
+ * @param args
+ * an array of strings with paramter-value paris in the form
+ * "{paramter-name}={paramter-value}"
+ * @param reportNotFound
+ * if paramters not found should result in a console notification and
+ * if errors in invocation should be reported, false otherwise
+ */
+ public void assignParameters(String[] args, boolean reportNotFound) {
+ // List allAccessors = retrieveAllAccessors();
+ List allAccessors = null;
+ try {
+ allAccessors = PropertyAccessor.determineReadWriteAccessors(this, Scape.class, false);
+ } catch (IntrospectionException e) {
+ throw new RuntimeException(e);
+ }
+
+ for (String arg : args) {
+ String paramName = PropertyAccessor.paramName(arg);
+ if (paramName != null) {
+ boolean found = false;
+ String paramValue = PropertyAccessor.paramValue(arg);
+ for (Iterator iterator = allAccessors.iterator(); iterator.hasNext();) {
+ PropertyAccessor accessor = (PropertyAccessor) iterator.next();
+ if (accessor.getName().equalsIgnoreCase(paramName)) {
+ try {
+ accessor.setAsText(paramValue);
+ } catch (InvocationTargetException e) {
+ if (reportNotFound) {
+ throw new RuntimeException("Exception in called method: " + e.getTargetException());
+ }
+ // Else ignore, its ok if there is a problem calling
+ // the method at this point
+ }
+ found = true;
+ }
+ }
+
+ found = found || Runner.assignEnvironmentParameter(paramName, paramValue);
+ if (!found) {
+ if (paramName.equalsIgnoreCase("RandomSeed")) {
+ try {
+ setRandomSeed(PropertyAccessor.paramValueLong(arg));
+ } catch (NumberFormatException e) {
+ getEnvironment().getConsole().println("Couldn't decode random seed value: " + paramValue);
+ }
+ found = true;
+ } else if (paramName.equalsIgnoreCase("StopPeriod")) {
+ try {
+ setStopPeriod(PropertyAccessor.paramValueInt(arg));
+ found = true;
+ } catch (SpatialTemporalException e) {
+ e.printStackTrace(); // To change body of catch
+ // statement use File | Settings
+ // | File Templates.
+ }
+ } else if (paramName.equalsIgnoreCase("PausePeriod")) {
+ setPausePeriod(PropertyAccessor.paramValueInt(arg));
+ found = true;
+ } else if (paramName.equalsIgnoreCase("AutoRestart")) {
+ setAutoRestart(PropertyAccessor.paramValueBoolean(arg));
+ found = true;
+ }
+ }
+ if (!found && reportNotFound) {
+ getEnvironment().getConsole().println("***WARNING: Parameter not found: " + paramName + " in " + getName());
+ }
+ }
+ }
+ }
+
+ public void createViews(String[] args) {
+ if (args != null) {
+ for (String arg : args) {
+ if (PropertyAccessor.paramName(arg).equals("view")) {
+ ScapeListener newView = (ScapeListener) getRunner().instanceFromName(PropertyAccessor.paramValue(arg));
+ if (newView != null) {
+ addView(newView);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets values for the models paramters based on supplied array of key value
+ * pairs, reporting if any of the keys (parameter names) are not found.
+ * Paramters and values are expected to be seperated with an "=", for example:
+ * "MyParameter=12".
+ *
+ * @param args
+ * an array of strings with paramter-value paris in the form
+ * "{paramter-name}={paramter-value}"
+ */
+ public void assignParameters(String[] args) {
+ assignParameters(args, true);
+ }
+
+ /**
+ * Moves an agent toward the specified agent.
+ *
+ * @param origin
+ * the agent moving
+ * @param target
+ * the agent's target
+ * @param distance
+ * the distance to move
+ */
+ public final void moveAway(LocatedAgent origin, Coordinate target, double distance) {
+ getSpace().moveAway(origin, target, distance);
+ }
+
+ /**
+ * Moves an agent toward the specified agent. It is an error to call this
+ * method on collections (and discrete discrete scapes not composed of
+ * HostCells.
+ *
+ * @param origin
+ * the agent moving
+ * @param target
+ * the agent's target
+ * @param distance
+ * the distance to move
+ */
+ public final void moveToward(LocatedAgent origin, Coordinate target, double distance) {
+ getSpace().moveToward(origin, target, distance);
+ }
+
+ /**
+ * Returns the shortest distance between one agent and another.
+ *
+ * @param origin
+ * the starting agent
+ * @param target
+ * the ending agent
+ */
+ public double calculateDistance(LocatedAgent origin, LocatedAgent target) {
+ return calculateDistance(origin.getCoordinate(), target.getCoordinate());
+ }
+
+ /**
+ * Returns the shortest distance between one LocatedAgent and another.
+ * Warning: this default method only returns a coordinate specific distance.
+ * It uses no information about the scape context; for example wether it is a
+ * periodic (wrapping) space or not. Therefore, if you implement your own
+ * versions of Scape, ensure that you have properly implemented a version of
+ * this method. (All Ascape Scape collections properly overide this method.)
+ *
+ * @param origin
+ * one LocatedAgent
+ * @param target
+ * another LocatedAgent
+ */
+ public final double calculateDistance(Coordinate origin, Coordinate target) {
+ return getSpace().calculateDistance(origin, target);
+ }
+
+ public class ConditionalIterator implements Iterator {
+
+ Iterator iter;
+
+ Conditional condition;
+
+ Object next;
+
+ public ConditionalIterator(Iterator iter, Conditional condition) {
+ ConditionalIterator.this.iter = iter;
+ ConditionalIterator.this.condition = condition;
+ loadNext();
+ }
+
+ private void loadNext() {
+ next = null;
+ while (iter.hasNext() && next == null) {
+ Object o = iter.next();
+ if (condition.meetsCondition(o)) {
+ next = o;
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ public Object next() {
+ if (next != null) {
+ Object currentNext = next;
+ loadNext();
+ return currentNext;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can't remove from a conditional iterator.");
+ }
+ }
+
+ /**
+ * Find the maximum cell of some data point. If multiple points have the same
+ * value, returns a random instance at that value.
+ *
+ * @param condition
+ * @return
+ */
+ public final List find(Conditional condition) {
+ return space.find(condition);
+ }
+
+ /**
+ * Find the maximum cell of some data point. If multiple points have the same
+ * value, returns a random instance at that value.
+ *
+ * @param iter
+ * @param dataPoint
+ * @return
+ */
+ public final LocatedAgent findMaximum(final Iterator iter, DataPoint dataPoint) {
+ // The code is written in such a way that there will not be the cost of
+ // Array creation if only one maximum exists
+ ArrayList multipleMaxObjects = null;
+ double maxValue = -Double.MAX_VALUE;
+ LocatedAgent maxObject = null;
+ while (iter.hasNext()) {
+ Object next = iter.next();
+ if (dataPoint.getValue(next) > maxValue) {
+ maxValue = dataPoint.getValue(next);
+ maxObject = (LocatedAgent) next;
+ multipleMaxObjects = null;
+ }
+ // Awaiting decision to become depndent on 1.4
+ // else if (Double.compare(dataPoint.getValue(next), maxValue) == 0)
+ // {
+ else if (DataPointConcrete.equals(dataPoint.getValue(next), maxValue)) {
+ if (multipleMaxObjects == null) {
+ multipleMaxObjects = new ArrayList();
+ multipleMaxObjects.add(maxObject);
+ }
+ multipleMaxObjects.add(next);
+ }
+ }
+ if (multipleMaxObjects == null) {
+ return maxObject;
+ } else {
+ return (LocatedAgent) multipleMaxObjects.get(randomToLimit(multipleMaxObjects.size()));
+ }
+ }
+
+ public final LocatedAgent findMinimumWithin(Coordinate coordinate, DataPoint dataPoint, Conditional condition, boolean includeSelf, double distance) {
+ return (LocatedAgent) getSpace().findMinimumWithin(coordinate, dataPoint, condition, includeSelf, distance);
+ }
+
+ public final LocatedAgent findMaximumWithin(Coordinate coordinate, DataPoint dataPoint, Conditional condition, boolean includeSelf, double distance) {
+ return (LocatedAgent) getSpace().findMaximumWithin(coordinate, dataPoint, condition, includeSelf, distance);
+ }
+
+ public final LocatedAgent findMinimum(final Iterator iter, DataPoint dataPoint) {
+ // The code is written in such a way that there will not be the cost of
+ // Array creation if only one minimum exists
+ ArrayList multipleMinObjects = null;
+ double minValue = Double.MAX_VALUE;
+ LocatedAgent minObject = null;
+ while (iter.hasNext()) {
+ Object next = iter.next();
+ if (dataPoint.getValue(next) < minValue) {
+ minValue = dataPoint.getValue(next);
+ minObject = (LocatedAgent) next;
+ multipleMinObjects = null;
+ }
+ // Awaiting decision to become depndent on 1.4
+ // else if (Double.compare(dataPoint.getValue(next), minValue) == 0)
+ // {
+ else if (DataPointConcrete.equals(dataPoint.getValue(next), minValue)) {
+ if (multipleMinObjects == null) {
+ multipleMinObjects = new ArrayList();
+ multipleMinObjects.add(minObject);
+ }
+ multipleMinObjects.add(next);
+ }
+ }
+ if (multipleMinObjects == null) {
+ return minObject;
+ } else {
+ return (LocatedAgent) multipleMinObjects.get(randomToLimit(multipleMinObjects.size()));
+ }
+ }
+
+ /**
+ * Returns an iteration across all agents the specified distance from the
+ * origin.
+ *
+ * @param origin
+ * the starting cell
+ * @param includeSelf
+ * should the origin be included
+ * @param distance
+ * the distance agents must be within to be included
+ */
+ public final Iterator withinIterator(final Coordinate origin, Conditional condition, boolean includeSelf, final double distance) {
+ return getSpace().withinIterator(origin, condition, includeSelf, distance);
+ }
+
+ /**
+ * Returns the agent with the minimum value.
+ *
+ * @param point
+ * the data point to use to make the comparison for minimum
+ */
+ public LocatedAgent findMinimum(DataPoint point) {
+ return findMinimum(iterator(), point);
+ }
+
+ /**
+ * Returns the agent with the maximum value.
+ *
+ * @param point
+ * the data point to use to make the comparison for maximum
+ */
+ public LocatedAgent findMaximum(DataPoint point) {
+ return findMaximum(iterator(), point);
+ }
+
+ /**
+ * The strategy that will be used to execute rules across this scape.
+ */
+ private ExecutionStrategy strategy;
+
+ private static int threadCount = 1;
+
+ /**
+ * Finds the nearest agent that meets some condition. Scapes without
+ * coordinate meaing should override this method.
+ *
+ * @param origin
+ * the coordinate to find agents near
+ * @param condition
+ * the condition that found agent must meet
+ * @param includeOrigin
+ * if the origin should be included
+ * @param distance
+ * the maximum distance around the origin to look
+ */
+ public final LocatedAgent findNearest(final Coordinate origin, Conditional condition, boolean includeOrigin, double distance) {
+ return (LocatedAgent) getSpace().findNearest(origin, condition, includeOrigin, distance);
+ }
+
+ /**
+ * Returns a coordinate randomly selected from the collection's space.
+ */
+ public final Coordinate findRandomCoordinate() {
+ return getSpace().findRandomCoordinate();
+ }
+
+ /**
+ * Returns all agents within the specified distance of the agent.
+ *
+ * @param origin
+ * the coordinate at the center of the search
+ * @param includeSelf
+ * whether or not the starting agent should be included in the search
+ * @param distance
+ * the distance agents must be within to be included
+ */
+ public final List findWithin(Coordinate origin, Conditional condition, boolean includeSelf, double distance) {
+ return getSpace().findWithin(origin, condition, includeSelf, distance);
+ }
+
+ /**
+ * Returns the number of agents within the specified distance of the agent
+ * that meet some condition.
+ *
+ * @param origin
+ * the coordinate at the center of the search
+ * @param condition
+ * the condition the agent must meet to be included
+ * @param distance
+ * the distance agents must be within to be included
+ */
+ public final int countWithin(Coordinate origin, Conditional condition, boolean includeSelf, double distance) {
+ return getSpace().countWithin(origin, condition, includeSelf, distance);
+ }
+
+ /**
+ * Returns if there are agents within the specified distance of the origin
+ * that meet some Condition.
+ *
+ * @param origin
+ * the coordinate at the center of the search
+ * @param condition
+ * the condition the agent must meet to be included
+ * @param distance
+ * the distance agents must be within to be included
+ */
+ public final boolean hasWithin(final Coordinate origin, Conditional condition, boolean includeSelf, double distance) {
+ return getSpace().hasWithin(origin, condition, includeSelf, distance);
+ }
+
+ public final boolean isMutable() {
+ return getSpace().isMutable();
+ }
+
+ /**
+ * Returns a string composed of descriptions of the contents.
+ */
+ public String contentsToString() {
+ String contents = "";
+ for (Iterator iterator = space.iterator(); iterator.hasNext();) {
+ Agent agent = (Agent) iterator.next();
+ contents = contents + agent.toString();
+ if (iterator.hasNext()) {
+ contents = contents + ", ";
+ }
+ }
+ return contents;
+ }
+
+ /**
+ * Returns a string representation of this scape.
+ */
+ public String toString() {
+ if (name != null) {
+ return name;
+ } else {
+ if (isRoot()) {
+ return "Root Scape";
+ } else if (prototypeAgent != null) {
+ return "Scape of " + prototypeAgent.toString() + "(s)";
+ } else {
+ return "Scape of agents of unspecified type";
+ }
+ }
+ }
+
+ public boolean isSerializable() {
+ return serializable;
+ }
+
+ public void setSerializable(boolean serializable) {
+ this.serializable = serializable;
+ }
+
+ /**
+ * Overides the clone method to do a deep clone of member state so that such
+ * state will not be shared between scapes.
+ */
+ public Object clone() {
+ Scape clone = (Scape) super.clone();
+ clone.scapeListeners = new ArrayList();
+ for (Iterator iter = scapeListeners.iterator(); iter.hasNext();) {
+ ScapeListener thisListener = (ScapeListener) iter.next();
+ try {
+ ScapeListener newListener = (ScapeListener) thisListener.clone();
+ removeScapeListener(newListener);
+ newListener.scapeRemoved(new ScapeEvent(this, ScapeEvent.REPORT_REMOVED));
+ newListener.scapeAdded(new ScapeEvent(clone, ScapeEvent.REPORT_ADDED));
+ clone.addScapeListener(newListener);
+ } catch (TooManyListenersException e) {
+ throw new RuntimeException("Internal error in Scape.clone " + e);
+ }
+ }
+ if (prototypeAgent != null) {
+ clone.prototypeAgent = (Agent) prototypeAgent.clone();
+ }
+ if (rules != null) {
+ clone.rules = (VectorSelection) rules.clone();
+ }
+ if (initialRules != null) {
+ clone.initialRules = (VectorSelection) initialRules.clone();
+ }
+ clone.drawFeatures = (Vector) drawFeatures.clone();
+ clone.space = (CollectionSpace) space.clone();
+ return clone;
+ }
+
+ /**
+ * Returns an agent randomly selected from the collection. If no agents exist,
+ * returns null.
+ */
+ public final LocatedAgent findRandom() {
+ return (LocatedAgent) getSpace().findRandom();
+ }
+
+ /**
+ * Returns a random unoccupied discrete location in the space given with the
+ * lattice.
+ *
+ * @param excludeAgent
+ * a cell to exclude from get (typically origin)
+ */
+ public Agent findRandom(Location excludeAgent) {
+ return (LocatedAgent) getSpace().findRandom(excludeAgent);
+ }
+
+ /**
+ * Returns an agent randomly that matches a condition. Note: If there are no
+ * agents in the collection that meet the condition, the method returns null.
+ *
+ * @param condition
+ * the condition that must be matched
+ */
+ public final Agent findRandom(Conditional condition) {
+ return (LocatedAgent) getSpace().findRandom(condition);
+ }
+
+ /**
+ * Creates a new agent in this collection by cloning the prototype agent,
+ * adding it in an arbitrary place (typically at the end of a list), and
+ * initializing it.
+ */
+ public synchronized Agent newAgent() {
+ return newAgent(false);
+ }
+
+ /**
+ * Creates a new agent in this collection by cloning the prototype agent,
+ * adding it to a random or arbitrary (last in most cases) place in the
+ * collection, and initializing it.
+ *
+ * @param randomLocation
+ * should the agent be placed in a random location, or in an
+ * arbitrary location?
+ */
+ public synchronized Agent newAgent(boolean randomLocation) {
+ Agent newAgent = (LocatedAgent) getSpace().newLocation(randomLocation);
+ List agents = new LinkedList();
+ agents.add(newAgent);
+ execute(getInitialRules().getVector(), agents);
+ return newAgent;
+ }
+
+ /**
+ * Returns the number of agents in the scape.
+ *
+ * @return the number of agents in the scape
+ */
+ public int size() {
+ return getSize();
+ }
+
+ /**
+ * Are there no agents in this scape?
+ *
+ * @return true if the scape is empty
+ */
+ public final boolean isEmpty() {
+ return getSpace().isEmpty();
+ }
+
+ /**
+ * Returns true if the scape collection contains the object (agent.)
+ *
+ * @param o
+ * the agent to search for
+ * @return true if the scape contains the agent
+ */
+ public final boolean contains(Object o) {
+ return getSpace().contains(o);
+ }
+
+ /**
+ * Returns an array containing all of the elements in this collection in
+ * proper sequence. Obeys the general contract of the
+ * <tt>Collection.toArray</tt> method.
+ *
+ * @return an array containing all of the elements in this collection in
+ * proper sequence.
+ * @see java.util.Arrays#asList(java.lang.Object[])
+ */
+ public final Object[] toArray() {
+ return getSpace().toArray();
+ }
+
+ /**
+ * Returns an array containing the current agents in this scape; the runtime
+ * type is specified by the passed array.
+ *
+ * @param a
+ * the array to copy the agents to
+ * @return an array containing the agents
+ * @throws java.lang.ArrayStoreException
+ * if the runtime type of the specified array doesn't match all
+ * agents
+ */
+ public final Object[] toArray(Object a[]) {
+ return getSpace().toArray(a);
+ }
+
+ /**
+ * Returns true if this collection contains all of agents in the specified
+ * collection.
+ *
+ * @param c
+ * collection of agents to be found in the scape
+ * @return true if this scape contains all of the agents in the collection
+ */
+ public final boolean containsAll(Collection c) {
+ return getSpace().containsAll(c);
+ }
+
+ /**
+ * Adds all of the agent in the specified collection to the end of the scape.
+ * Assumes (but does not check) that all of the elements are instances of
+ * agent.
+ *
+ * @param c
+ * collection whose agents are to be added to the scape
+ * @return true if the scape had new agents added
+ */
+ public final boolean addAll(Collection c) {
+ return getSpace().addAll(c);
+ }
+
+ /**
+ * Removes all of the agnets contained in the collection. No attempt is made
+ * to cache the removal; the agents are all removed at once.
+ *
+ * @param c
+ * collection whose agents are to be added to the scape
+ * @return true if the scape had agents (but not neccessarily all?) removed
+ */
+ public final boolean removeAll(Collection c) {
+ return getSpace().removeAll(c);
+ }
+
+ /**
+ * Retains only the elements in the scape that are in the specified
+ * collection.
+ *
+ * @param c
+ * collection whose agents are to be retained in the scape
+ * @return true if this scape had agents removed
+ */
+ public final boolean retainAll(Collection c) {
+ return getSpace().retainAll(c);
+ }
+
+ /**
+ * Removes all agents from the scape.
+ */
+ public final void clear() {
+ getSpace().clear();
+ }
+
+ /**
+ * Adds the supplied object (agent) to this collection.
+ */
+ public boolean add(Object a) {
+ return add(a, true);
+ }
+
+ /**
+ * Adds the supplied object (assumed to be an agent) to this collection. The
+ * object is assumed to be an agent, though that behavior may be loosened at
+ * some point.
+ *
+ * @param agent
+ * the agent to add
+ * @param isParent
+ * should this scape be made the parent scape of the agent?
+ * @throws UnsupportedOperationException
+ * if this scape's space is not a list.
+ */
+ public final boolean add(Object agent, boolean isParent) {
+ if (!(agent instanceof Agent)) {
+ // This may change at some point..
+ throw new ClassCastException("Scape collections expect Agents only.");
+ }
+ boolean success = getSpace().add(agent, isParent);
+ if (isParent) {
+ ((Agent) agent).setScape(this);
+ }
+ return success;
+ }
+
+ /**
+ * Adds the supplied object (agent) to this collection.
+ *
+ * @throws UnsupportedOperationException
+ * if this scape's space is not a list.
+ */
+ public final void add(int index, Object a) {
+ add(index, a, true);
+ }
+
+ /**
+ * Adds the supplied object (assumed to be an agent) to this collection. The
+ * object is assumed to be an agent, though that behavior may be loosened at
+ * some point.
+ *
+ * @param o
+ * the agent to add
+ * @param isParent
+ * should this scape be made the parent scape of the agent?
+ * @throws UnsupportedOperationException
+ * if this scape's space is not a list.
+ */
+ public final void add(int index, Object o, boolean isParent) {
+ try {
+ ((ListSpace) getSpace()).add(index, o, isParent);
+ if (isParent) {
+ ((Agent) o).setScape(this);
+ }
+ } catch (ClassCastException e) {
+ throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
+ }
+ }
+
+ /**
+ * Removes the supplied object (agent) from this collection.
+ *
+ * @param o
+ * the agent to be removed
+ * @return true if the agent was deleted, false otherwise
+ */
+ public boolean remove(Object o) {
+ return space.remove(o);
+ }
+
+ /**
+ * Removes the object at the index from this collection.
+ *
+ * @param index
+ * the index for the agent to remove
+ * @throws UnsupportedOperationException
+ * if this scape's space is not a list.
+ */
+ public final Object remove(int index) {
+ try {
+ return ((List) getSpace()).remove(index);
+ } catch (ClassCastException e) {
+ throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
+ }
+ }
+
+ /**
+ * Returns the cell existing at the specified coordinate.
+ */
+ public final LocatedAgent get(Coordinate coordinate) {
+ return (LocatedAgent) getSpace().get(coordinate);
+ }
+
+ /**
+ * Sets the agent at the specified coordinate to the supplied agent.
+ *
+ * @param coordinate
+ * the coordinate to add the agent at
+ * @param agent
+ * the agent to add
+ */
+ public final void set(Coordinate coordinate, LocatedAgent agent, boolean isParent) {
+ getSpace().set(coordinate, agent);
+ if (isParent) {
+ agent.setScape(getScape());
+ agent.setCoordinate(coordinate);
+ }
+ }
+
+ /**
+ * Sets the agent at the specified coordinate to the supplied agent.
+ *
+ * @param coordinate
+ * the coordinate to add the agent at
+ * @param agent
+ * the agent to add
+ */
+ public void set(Coordinate coordinate, LocatedAgent agent) {
+ set(coordinate, agent, true);
+ }
+
+ /**
+ * Returns the cell existing at the specified location. Convenience method.
+ *
+ * @throws UnsupportedOperationException
+ * if this scape's space is not a list.
+ */
+ public final Object get(int index) {
+ try {
+ return ((ListBase) getSpace()).get(index);
+ } catch (ClassCastException e) {
+ throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
+ }
+ }
+
+ /**
+ * Sets the specified location to the provided agent. Convenience method.
+ *
+ * @throws UnsupportedOperationException
+ * if this scape's space is not a list.
+ */
+ public void set(int index, Object agent) {
+ set(index, agent, true);
+ }
+
+ /**
+ * Sets the specified location to the provided agent. Convenience method.
+ *
+ * @throws UnsupportedOperationException
+ * if this scape's space is not a list.
+ */
+ public void set(int index, Object agent, boolean isParent) {
+ try {
+ ((ListBase) getSpace()).set(index, (LocatedAgent) agent, isParent);
+ if (isParent) {
+ ((Agent) agent).setScape(this);
+ }
+ } catch (ClassCastException e) {
+ throw new UnsupportedOperationException("Underlying space is not a list and cannot be accessed randomly.");
+ }
+ }
+
+ public final ResetableIterator scapeIterator() {
+ return getSpace().safeIterator();
+ }
+
+ public final RandomIterator scapeRandomIterator() {
+ return getSpace().safeRandomIterator();
+ }
+
+ protected final ResetableIterator scapeIterator(int start, int limit) {
+ return getSpace().safeIterator(start, limit);
+ }
+
+ public boolean isPeriodic() {
+ return getSpace().isPeriodic();
+ }
+
+ public void setPeriodic(boolean periodic) {
+ getSpace().setPeriodic(periodic);
+ }
+
+ public Scape getSuperScape() {
+ return getSpace() instanceof SubSpace ? (Scape) ((SubSpace) getSpace()).getSuperSpace().getContext() : null;
+ }
+
+ public void setSuperScape(Scape superScape) {
+ try {
+ ((SubSpace) getSpace()).setSuperSpace(superScape.getSpace());
+ } catch (ClassCastException e) {
+ throw new UnsupportedOperationException("Underlying scape is no a SubSpace.");
+ }
+ }
+
+ /**
+ * Returns multiple independently thread safe scape iterators across all
+ * agents in this scape.
+ *
+ * @return an iterator over the agents in scape order
+ */
+ public final ResetableIterator[] scapeIterators(int count) {
+ return getSpace().safeIterators(count);
+ }
+
+ public boolean isListenersAndMembersCurrent() {
+ return listenersAndMembersCurrent;
+ }
+
+ public final Space getSpace() {
+ return space;
+ }
+
+ public void setSpace(Space space) {
+ this.space = space;
+ // todo remove circular dependency
+ space.setContext(this);
+ space.setRandom(getRandom());
+ }
+
+ /**
+ * Sets the size of the collection, filling with clones of prototype agent. It
+ * is an error to set size while a scape is running.
+ *
+ * @param size
+ * a coordinate describing the size of this scape
+ */
+ public void setSize(int size) {
+ if (runner != null && runner.isRunning()) {
+ throw new RuntimeException("Tried to set size while scape was running");
+ }
+ space.setSize(size);
+ }
+
+ public int getThreadCount() {
+ return Scape.threadCount;
+ }
+
+ public void setThreadCount(int threadCount) {
+ Scape.threadCount = threadCount;
+ }
+
+ public Location getPrototype() {
+ return (Location) getPrototypeAgent();
+ }
+
+ public boolean isHome(Location a) {
+ return ((Agent) a).getScape() == this;
+ }
+
+ /**
+ * Convenience method for obtaining sata for current run.
+ *
+ * @return the Runner's Data Group.
+ */
+ public DataGroup getData() {
+ return getRunner().getData();
+ }
+
+ /**
+ * Returns the UI Environment.
+ *
+ * @return a UI environment appropriate for given UI.
+ * @deprecated retained for backward compatability, please use
+ * #getUIEnvironment instead.
+ */
+ public AbstractUIEnvironment getUserEnvironment() {
+ return getUIEnvironment();
+ }
}
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ControlEvent.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ControlEvent.java
index 56832d83..2db736b6 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ControlEvent.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ControlEvent.java
@@ -20,149 +20,147 @@ import java.util.EventObject;
*/
public class ControlEvent extends EventObject {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * A listener of the target has been updated.
- */
- public final static int REPORT_LISTENER_UPDATED = 1;
-
- /**
- * The target is requested to start.
- */
- public final static int REQUEST_START = 2;
-
- /**
- * The target is requested to stop.
- */
- public final static int REQUEST_STOP = 3;
-
- /**
- * The target is requested to step one iteration.
- */
- public final static int REQUEST_STEP = 4;
-
- /**
- * The target is requested to restart; that is, stop and start from initial
- * state.
- */
- public final static int REQUEST_RESTART = 5;
-
- /**
- * The target is requested to pause.
- */
- public final static int REQUEST_PAUSE = -1;
-
- /**
- * The target is requested to resume.
- */
- public final static int REQUEST_RESUME = -2;
-
- /**
- * The target is requested to exit.
- */
- public final static int REQUEST_QUIT = -3;
-
- /**
- * The target is requested to save itself.
- */
- public final static int REQUEST_SAVE = -4;
-
- /**
- * The target is requested to open another model.
- */
- public final static int REQUEST_CLOSE = -5;
-
- /**
- * The target is requested to open another model, saving itself first.
- */
- public final static int REQUEST_OPEN = -6;
-
- /**
- * The target is requested to open a saved run, saving itself first.
- */
- public final static int REQUEST_OPEN_SAVED = -7;
-
- /**
- * The id.
- */
- private int id;
-
- /**
- * Constructs a control event, used to control a scape.
- *
- * @param source
- * the object firing this alert event.
- * @param id
- * the id
- */
- public ControlEvent(Object source, int id) {
- super(source);
- this.id = id;
- }
-
- /**
- * Gets the id decribing the control event.
- *
- * @return the ID
- */
- public int getID() {
- return id;
- }
-
- /**
- * Returns a paramter string describing this event.
- *
- * @return the string
- */
- public String paramString() {
- String typeStr;
- switch (id) {
- case REPORT_LISTENER_UPDATED:
- typeStr = "Report listener updated";
- break;
- case REQUEST_START:
- typeStr = "Request start";
- break;
- case REQUEST_STEP:
- typeStr = "Request step";
- break;
- case REQUEST_STOP:
- typeStr = "Request stop";
- break;
- case REQUEST_PAUSE:
- typeStr = "Request pause";
- break;
- case REQUEST_RESUME:
- typeStr = "Request resume";
- break;
- case REQUEST_QUIT:
- typeStr = "Request scape quit";
- break;
- case REQUEST_SAVE:
- typeStr = "Request save";
- break;
- case REQUEST_OPEN:
- typeStr = "Request open";
- break;
- case REQUEST_OPEN_SAVED:
- typeStr = "Request open a saved run";
- break;
- default:
- typeStr = "Unknown request";
- }
- return typeStr;
- }
-
- /**
- * Returns a string describing this event.
- *
- * @return the string
- */
- public String toString() {
- return paramString() + " from " + getSource();
- }
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * A listener of the target has been updated.
+ */
+ public final static int REPORT_LISTENER_UPDATED = 1;
+
+ /**
+ * The target is requested to start.
+ */
+ public final static int REQUEST_START = 2;
+
+ /**
+ * The target is requested to stop.
+ */
+ public final static int REQUEST_STOP = 3;
+
+ /**
+ * The target is requested to step one iteration.
+ */
+ public final static int REQUEST_STEP = 4;
+
+ /**
+ * The target is requested to restart; that is, stop and start from initial
+ * state.
+ */
+ public final static int REQUEST_RESTART = 5;
+
+ /**
+ * The target is requested to pause.
+ */
+ public final static int REQUEST_PAUSE = -1;
+
+ /**
+ * The target is requested to resume.
+ */
+ public final static int REQUEST_RESUME = -2;
+
+ /**
+ * The target is requested to exit.
+ */
+ public final static int REQUEST_QUIT = -3;
+
+ /**
+ * The target is requested to save itself.
+ */
+ public final static int REQUEST_SAVE = -4;
+
+ /**
+ * The target is requested to open another model.
+ */
+ public final static int REQUEST_CLOSE = -5;
+
+ /**
+ * The target is requested to open another model, saving itself first.
+ */
+ public final static int REQUEST_OPEN = -6;
+
+ /**
+ * The target is requested to open a saved run, saving itself first.
+ */
+ public final static int REQUEST_OPEN_SAVED = -7;
+
+ /**
+ * The id.
+ */
+ private int id;
+
+ /**
+ * Constructs a control event, used to control a scape.
+ *
+ * @param source
+ * the object firing this alert event.
+ * @param id
+ * the id
+ */
+ public ControlEvent(Object source, int id) {
+ super(source);
+ this.id = id;
+ }
+
+ /**
+ * Gets the id decribing the control event.
+ *
+ * @return the ID
+ */
+ public int getID() {
+ return id;
+ }
+
+ /**
+ * Returns a paramter string describing this event.
+ *
+ * @return the string
+ */
+ public String paramString() {
+ String typeStr;
+ switch (id) {
+ case REPORT_LISTENER_UPDATED:
+ typeStr = "Report listener updated";
+ break;
+ case REQUEST_START:
+ typeStr = "Request start";
+ break;
+ case REQUEST_STEP:
+ typeStr = "Request step";
+ break;
+ case REQUEST_STOP:
+ typeStr = "Request stop";
+ break;
+ case REQUEST_PAUSE:
+ typeStr = "Request pause";
+ break;
+ case REQUEST_RESUME:
+ typeStr = "Request resume";
+ break;
+ case REQUEST_QUIT:
+ typeStr = "Request scape quit";
+ break;
+ case REQUEST_SAVE:
+ typeStr = "Request save";
+ break;
+ case REQUEST_OPEN:
+ typeStr = "Request open";
+ break;
+ case REQUEST_OPEN_SAVED:
+ typeStr = "Request open a saved run";
+ break;
+ default:
+ typeStr = "Unknown request";
+ }
+ return typeStr;
+ }
+
+ /**
+ * Returns a string describing this event.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return paramString() + " from " + getSource();
+ }
}
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/DefaultScapeListener.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/DefaultScapeListener.java
index 72b5d50f..17f52b79 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/DefaultScapeListener.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/DefaultScapeListener.java
@@ -30,9 +30,6 @@ import org.ascape.model.Scape;
*/
public abstract class DefaultScapeListener implements ScapeListener, Serializable {
- /**
- *
- */
private static final long serialVersionUID = 1L;
/**
@@ -99,6 +96,9 @@ public abstract class DefaultScapeListener implements ScapeListener, Serializabl
public void scapeStopped(ScapeEvent scapeEvent) {
}
+ public void scapePaused(ScapeEvent scapeEvent) {
+ }
+
/**
* Called immediatly after scape is iterated.
*
@@ -213,6 +213,8 @@ public abstract class DefaultScapeListener implements ScapeListener, Serializabl
scapeDeserialized(scapeEvent);
} else if (scapeEvent.getID() == ScapeEvent.REQUEST_CLOSE) {
scapeClosing(scapeEvent);
+ } else if (scapeEvent.getID() == ScapeEvent.TICK) {
+ scapePaused(scapeEvent);
}
if (isNotifyScapeAutomatically()) {
notifyScapeUpdated();
@@ -304,11 +306,7 @@ public abstract class DefaultScapeListener implements ScapeListener, Serializabl
this.name = name;
}
- /**
- * Clones this object.
- *
- * @return the object
- */
+ @Override
public Object clone() {
try {
DefaultScapeListener clone = (DefaultScapeListener) super.clone();
@@ -324,6 +322,7 @@ public abstract class DefaultScapeListener implements ScapeListener, Serializabl
*
* @return the string
*/
+ @Override
public String toString() {
return getName();
}
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ScapeListener.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ScapeListener.java
index 31d1bfe2..05f55978 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ScapeListener.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/event/ScapeListener.java
@@ -30,140 +30,147 @@ import org.ascape.util.HasName;
*/
public interface ScapeListener extends EventListener, HasName, Cloneable {
- /**
- * Called immediatly after the scape is initialized.
- *
- * @param scapeEvent
- * the scape event
- */
- public void scapeInitialized(ScapeEvent scapeEvent);
-
- /**
- * Called immediatly after the scape is started.
- *
- * @param scapeEvent
- * the scape event
- */
- public void scapeStarted(ScapeEvent scapeEvent);
-
- /**
- * Called immediatly after the scape is stopped.
- *
- * @param scapeEvent
- * the scape event
- */
- public void scapeStopped(ScapeEvent scapeEvent);
-
- /**
- * Called immediatly after scape is iterated.
- *
- * @param scapeEvent
- * the scape event
- */
- public void scapeIterated(ScapeEvent scapeEvent);
-
- /**
- * Method called when the scape is ready for setup. That is, the scape has
- * been created (or it has just finished its previous run) but it has not
- * yet been initialized. This is an appropriate place to change model
- * paramters, persent user's with options, etc.
- *
- * @param scapeEvent
- * the scape event
- */
- public void scapeSetup(ScapeEvent scapeEvent);
-
- /**
- * Method called as the scape is about to be closed. Allows any final view
- * cleanup.
- *
- * @param scapeEvent
- * the scape event
- */
- public void scapeClosing(ScapeEvent scapeEvent);
-
- /**
- * Method called as the environment is about to quit. Note that this method
- * may not actually be called by a scape at all. Allows any final view
- * cleanup.
- *
- * @param scapeEvent
- * the scape event
- */
- public void environmentQuiting(ScapeEvent scapeEvent);
-
- /**
- * Method called immediatly after a model is deserialized.
- *
- * @param scapeEvent
- * the scape event
- */
- public void scapeDeserialized(ScapeEvent scapeEvent);
-
- /**
- * Informs the listener that the agent scape has some kind of notification
- * for the listener,.
- *
- * @param scapeEvent
- * the scape setup event
- */
- public void scapeNotification(ScapeEvent scapeEvent);
-
- /**
- * Notifies the listener that the scape has added it. This is in affect a
- * call back from the scape after adding the listener. At this point, the
- * listener is responsible for responding back to the scape upon any
- * notifications. A listener <i>typically</i> has one and only one scape,
- * see below. A "good citizen" listener will typically make certain that it
- * isn't added to more than one scape at a time, but one can also imagine
- * cases where a listener might be interested in the activities of many
- * scapes and this would be a perfectly legitimate usage pattern.
- *
- * @param scapeEvent
- * the scape add event
- * @throws TooManyListenersException
- * the too many listeners exception
- */
- public void scapeAdded(ScapeEvent scapeEvent) throws TooManyListenersException;
-
- /**
- * Removes the scape from this view. Typically there should ony be one scape
- * to remove. This method must be called whenever a listener is destroyed or
- * becomes unresponsive; otherwise the model will wait indefinetly for the
- * listener's updated response.
- *
- * @param scapeEvent
- * the scape removed event
- * @see scapeAdded
- */
- public void scapeRemoved(ScapeEvent scapeEvent);
-
- /**
- * Returns true if the listener is a graphical user interface component.
- *
- * @return true, if is graphic
- */
- public boolean isGraphic();
-
- /**
- * Returns true if the listener is intended to be used only for the current
- * scape; typical of all but control related listeners.
- *
- * @return true, if is life of scape
- */
- public boolean isLifeOfScape();
-
- /**
- * Returns the Scape being viewed.
- *
- * @return the scape
- */
- public Scape getScape();
-
- /**
- * Require public access for clone.
- *
- * @return the object
- */
- public Object clone();
+ /**
+ * Called immediatly after the scape is initialized.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void scapeInitialized(ScapeEvent scapeEvent);
+
+ /**
+ * Called immediatly after the scape is started.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void scapeStarted(ScapeEvent scapeEvent);
+
+ /**
+ * Called immediatly after the scape is stopped.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void scapeStopped(ScapeEvent scapeEvent);
+
+ /**
+ * Called immediately after the scape has been set to pause.
+ *
+ * @param scapeEvent
+ */
+ public void scapePaused(ScapeEvent scapeEvent);
+
+ /**
+ * Called immediatly after scape is iterated.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void scapeIterated(ScapeEvent scapeEvent);
+
+ /**
+ * Method called when the scape is ready for setup. That is, the scape has
+ * been created (or it has just finished its previous run) but it has not yet
+ * been initialized. This is an appropriate place to change model paramters,
+ * persent user's with options, etc.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void scapeSetup(ScapeEvent scapeEvent);
+
+ /**
+ * Method called as the scape is about to be closed. Allows any final view
+ * cleanup.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void scapeClosing(ScapeEvent scapeEvent);
+
+ /**
+ * Method called as the environment is about to quit. Note that this method
+ * may not actually be called by a scape at all. Allows any final view
+ * cleanup.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void environmentQuiting(ScapeEvent scapeEvent);
+
+ /**
+ * Method called immediatly after a model is deserialized.
+ *
+ * @param scapeEvent
+ * the scape event
+ */
+ public void scapeDeserialized(ScapeEvent scapeEvent);
+
+ /**
+ * Informs the listener that the agent scape has some kind of notification for
+ * the listener,.
+ *
+ * @param scapeEvent
+ * the scape setup event
+ */
+ public void scapeNotification(ScapeEvent scapeEvent);
+
+ /**
+ * Notifies the listener that the scape has added it. This is in affect a call
+ * back from the scape after adding the listener. At this point, the listener
+ * is responsible for responding back to the scape upon any notifications. A
+ * listener <i>typically</i> has one and only one scape, see below. A
+ * "good citizen" listener will typically make certain that it isn't added to
+ * more than one scape at a time, but one can also imagine cases where a
+ * listener might be interested in the activities of many scapes and this
+ * would be a perfectly legitimate usage pattern.
+ *
+ * @param scapeEvent
+ * the scape add event
+ * @throws TooManyListenersException
+ * the too many listeners exception
+ */
+ public void scapeAdded(ScapeEvent scapeEvent) throws TooManyListenersException;
+
+ /**
+ * Removes the scape from this view. Typically there should ony be one scape
+ * to remove. This method must be called whenever a listener is destroyed or
+ * becomes unresponsive; otherwise the model will wait indefinetly for the
+ * listener's updated response.
+ *
+ * @param scapeEvent
+ * the scape removed event
+ * @see scapeAdded
+ */
+ public void scapeRemoved(ScapeEvent scapeEvent);
+
+ /**
+ * Returns true if the listener is a graphical user interface component.
+ *
+ * @return true, if is graphic
+ */
+ public boolean isGraphic();
+
+ /**
+ * Returns true if the listener is intended to be used only for the current
+ * scape; typical of all but control related listeners.
+ *
+ * @return true, if is life of scape
+ */
+ public boolean isLifeOfScape();
+
+ /**
+ * Returns the Scape being viewed.
+ *
+ * @return the scape
+ */
+ public Scape getScape();
+
+ /**
+ * Require public access for clone.
+ *
+ * @return the object
+ */
+ public Object clone();
}
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViews.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViews.java
index a50b6320..8e43cfbe 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViews.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViews.java
@@ -9,6 +9,7 @@ package org.ascape.model.rule;
import org.ascape.model.Agent;
import org.ascape.model.Scape;
+import org.ascape.model.event.ScapeEvent;
/**
* A rule causing the target to notify its views that an update has occured.
@@ -21,44 +22,37 @@ import org.ascape.model.Scape;
*/
public class NotifyViews extends PropogateScapeOnly {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- /**
- * The id.
- */
- private int id;
+ private static final long serialVersionUID = 1L;
- /**
- * Instantiates a new notify views.
- *
- * @param id
- * the id
- */
- public NotifyViews(int id) {
- super("Notify Views id: " + id);
- this.id = id;
- }
+ /**
+ * The id.
+ */
+ private int id;
- /**
- * Notify all views of state update.
- *
- * @param agent
- * the agent (scape) to notify veiws
- * @see Scape#notifyViews
- */
- public void execute(Agent agent) {
- //if (!((((Scape) agent).getPrototypeAgent()) instanceof AgentScape)) {
- ((Scape) agent).notifyViews(id);
- super.execute(agent);
- //}
- }
+ /**
+ * Instantiates a new notify views.
+ *
+ * @param id
+ * the id
+ */
+ public NotifyViews(int id) {
+ super("Notify Views id: " + id);
+ this.id = id;
+ }
+
+ /**
+ * Notify all views of state update.
+ *
+ * @param agent
+ * the agent (scape) to notify veiws
+ * @see Scape#notifyListeners(ScapeEvent)
+ */
+ @Override
+ public void execute(Agent agent) {
+ // if (!((((Scape) agent).getPrototypeAgent()) instanceof AgentScape)) {
+ ((Scape) agent).notifyListeners(id);
+ super.execute(agent);
+ // }
+ }
- /**
- * Only scapes can have views.
- */
- //public boolean isScapeOnly() {
- // return true;
- //}
}
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViewsEvent.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViewsEvent.java
index 9a65e83b..e8c7393f 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViewsEvent.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/model/rule/NotifyViewsEvent.java
@@ -21,37 +21,37 @@ import org.ascape.model.event.ScapeEvent;
*/
public class NotifyViewsEvent extends PropogateScapeOnly {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- /**
- * The event.
- */
- private ScapeEvent event;
-
- /**
- * Instantiates a new notify views event.
- *
- * @param event
- * the event
- */
- public NotifyViewsEvent(ScapeEvent event) {
- super("Notify Views id: " + event);
- this.event = event;
- }
-
- /**
- * Notify all views of state update.
- *
- * @param agent
- * the agent (scape) to notify veiws
- * @see org.ascape.model.Scape#notifyViews
- */
- public void execute(Agent agent) {
- //if (!((((Scape) agent).getPrototypeAgent()) instanceof AgentScape)) {
- ((Scape) agent).notifyViews(event);
- super.execute(agent);
- //}
- }
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The event.
+ */
+ private ScapeEvent event;
+
+ /**
+ * Instantiates a new notify views event.
+ *
+ * @param event
+ * the event
+ */
+ public NotifyViewsEvent(ScapeEvent event) {
+ super("Notify Views id: " + event);
+ this.event = event;
+ }
+
+ /**
+ * Notify all views of state update.
+ *
+ * @param agent
+ * the agent (scape) to notify veiws
+ * @see org.ascape.model.Scape#notifyListeners(ScapeEvent)
+ */
+ @Override
+ public void execute(Agent agent) {
+ // if (!((((Scape) agent).getPrototypeAgent()) instanceof AgentScape)) {
+ ((Scape) agent).notifyListeners(event);
+ super.execute(agent);
+ // }
+ }
+
}
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/NonGraphicRunner.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/NonGraphicRunner.java
index 4da1da35..fd298579 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/NonGraphicRunner.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/NonGraphicRunner.java
@@ -6,52 +6,53 @@ import org.ascape.model.Scape;
public class NonGraphicRunner extends Runner {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1L;
- @Override
- public void closeAndOpenSavedFinally(Scape oldScape) {
- throw new InternalError("Unexpected call to close and open for headless runtime.");
- }
+ @Override
+ public void closeAndOpenSavedFinally(Scape oldScape) {
+ throw new InternalError("Unexpected call to close and open for headless runtime.");
+ }
- @Override
- public void saveChoose() {
- throw new InternalError("Unexpected call to save and choose for headless runtime.");
- }
+ @Override
+ public void saveChoose() {
+ throw new InternalError("Unexpected call to save and choose for headless runtime.");
+ }
- /**
- * Creates, initializes and runs the model specified in the argument. To allow the running of a model directly from
- * the command line, you should subclass this method as shown below:
- *
- * <pre><code><BR>
- * public MyModel extends Model {
- * public static void main(String[] args) {
- * (open(&quot;mypath.MyModel&quot;)).start();
- * }
- * }
- * <BR>
- * </pre>
- *
- * </code> Otherwise, assuming your classpath is set up correctly, to invoke a model from the command line type:
- *
- * <pre><code><BR>
- * java org.ascape.model.Scape mypath.myModel
- * </pre>
- *
- * </code>
- *
- * @param args
- * at index 0; the name of the subclass of this class to run
- */
- public static void main(String[] args) {
- // Register environment
- Runner model = new NonGraphicRunner();
- try {
- model.launch(args);
- } catch (IOException e) {
- throw new RuntimeException("Exception attempting to load model.", e);
- }
- }
+ /**
+ * Creates, initializes and runs the model specified in the argument. To allow
+ * the running of a model directly from the command line, you should subclass
+ * this method as shown below:
+ *
+ * <pre>
+ * <code><BR>
+ * public MyModel extends Model {
+ * public static void main(String[] args) {
+ * (open(&quot;mypath.MyModel&quot;)).start();
+ * }
+ * }
+ * <BR>
+ * </pre>
+ *
+ * </code> Otherwise, assuming your classpath is set up correctly, to invoke a
+ * model from the command line type:
+ *
+ * <pre>
+ * <code><BR>
+ * java org.ascape.model.Scape mypath.myModel
+ * </pre>
+ *
+ * </code>
+ *
+ * @param args
+ * at index 0; the name of the subclass of this class to run
+ */
+ public static void main(String[] args) {
+ // Register environment
+ Runner model = new NonGraphicRunner();
+ try {
+ model.launch(args);
+ } catch (IOException e) {
+ throw new RuntimeException("Exception attempting to load model.", e);
+ }
+ }
}
diff --git a/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/Runner.java b/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/Runner.java
index 784fdda1..bd448940 100644
--- a/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/Runner.java
+++ b/org.ascape/plugins/org.ascape.core/src/org/ascape/runtime/Runner.java
@@ -42,1560 +42,1557 @@ import org.ascape.util.data.DataGroup;
*/
public abstract class Runner implements Serializable, Runnable {
- /**
- *
- */
- private static final long serialVersionUID = 6924379091134591724L;
-
- private Scape scape;
-
- /**
- * Data group for all scapes. At some point this may be made non-static.
- */
- private DataGroup dataGroup;
-
- /**
- * Should any scapes opened be started automatically? Default true. true.
- */
- private static boolean startOnOpen = true;
-
- /**
- * Manages user space UI, settings etc.
- */
- protected transient RuntimeEnvironment environment;
-
- /**
- * The unit of time each iteration or period represents.
- */
- private String periodName = "Iteration";
-
- /**
- * A brief descripiton (including credits) of the scape or of the model, if
- * this is root scape. Plaintext.
- */
- private String description;
-
- /**
- * A brief descripiton (including credits) of the scape or of the model, if
- * this is root scape. Includes HTML style tags as appropriate.
- */
- private String HTMLDescription;
-
- /**
- * Iteration to start on when restarting, creating new model, etc...
- */
- private int startPeriod = 0;
-
- /**
- * Iteration to stop on.
- */
- private int stopPeriod = Integer.MAX_VALUE;
-
- /**
- * Period to pause on.
- */
- private int pausePeriod = Integer.MAX_VALUE;
-
- /**
- * The system path in which all files are by default stored to and retrieved
- * from. The value of the system variable ascape home.
- */
- private String home;
-
- /**
- * The earliest period this scape is expected to be run at.
- */
- private int earliestPeriod;
-
- /**
- * The latest period this scape is expected to be run at.
- */
- private int latestPeriod = Integer.MAX_VALUE;
-
- private List restartingViews = new Vector();
-
- /**
- * The number of iterations since the scape began iterating.
- */
- private int iteration;
-
- /**
- * The current period.
- */
- private int period;
-
- /**
- * Is the scape currently paused?
- */
- private boolean paused = false;
-
- /**
- * Is the scape currently running?
- */
- private boolean running = false;
-
- /**
- * Has a step been requested?
- */
- private boolean step = false;
-
- /**
- * Has a restart been requested after the current run stops?
- */
- private boolean closeAndOpenNewRequested = false;
-
- /**
- * Has loading of a saved run been requested after the current run stops?
- */
- private boolean closeAndOpenSavedRequested = false;
-
- /*
- * All of the following will be replaced by a diferred control mechanism.
- */
-
- /**
- * Has a restart been requested after the current run stops?
- */
- private boolean restartRequested = false;
-
- /**
- * Has a close been requested after the current run stops?
- */
- private boolean closeRequested = false;
-
- /**
- * Has a quit been requested after the current run stops?
- */
- private boolean quitRequested = false;
-
- /**
- * Has an open been requested when the current iteration completes?
- */
- private boolean openRequested = false;
-
- /**
- * Has a save been requested when the current iteration completes?
- */
- private boolean saveRequested = false;
-
- /**
- * Are we currently in the main control loop?
- */
- private boolean inMainLoop = false;
-
- private boolean beginningDeserializedRun = false;
-
- /**
- * Should the scape be restarted automatically after being stopped?
- */
- private boolean autoRestart = true;
-
- /**
- * Indicates that GUI should be displayed, if false, not GUI under any
- * circumstances.
- */
- private static boolean displayGraphics = true;
-
- /**
- * Indicates that we are forwarding graphics to a client scape.
- */
- private static boolean serveGraphics = false;
-
- /**
- * Indicates that we are in a multiwin environment and want simple winsow
- * strucutures.
- */
- private static boolean muiltWinEnvironment;
-
- private Thread modelThread;
-
- public Runner() {
- this(new RuntimeEnvironment());
- }
-
- public Runner(RuntimeEnvironment environment) {
- this.environment = environment;
- }
-
- protected void initialize() {
- setInternalRunning(false);
- getData().clear();
- scape.reseed();
- scape.execute(new NotifyViews(ScapeEvent.REQUEST_SETUP));
- waitForViewsUpdate();
- setIteration(0);
- setPeriod(getStartPeriod());
- scape.execute(Scape.INITIALIZE_RULE);
- scape.execute(new NotifyViews(ScapeEvent.REPORT_INITIALIZED));
- waitForViewsUpdate();
- scape.execute(Scape.INITIAL_RULES_RULE);
- setInternalRunning(true);
- }
-
- /**
- * The main run loop of a running simulation. Seperated from run so that it
- * can be executed in different runtime modes.
- */
- protected synchronized void runMainLoop() {
- inMainLoop = true;
- restartRequested = false;
- if (beginningDeserializedRun) { // we are re-starting the main loop
- // after reading in a serialized model
- beginningDeserializedRun = false;
- saveRequested = false;
- initialize();
- scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_DESERIALIZED));
- waitForViewsUpdate();
- scape.reseed();
- getEnvironment().getConsole().println("\nNew Random Seed: " + scape.getRandomSeed() + "\n");
- } else { // !beginningDeserializedRun
- scape.executeOnRoot(Scape.CLEAR_STATS_RULE);
- initialize();
- scape.executeOnRoot(Scape.COLLECT_STATS_RULE);
- scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_START));
- waitForViewsUpdate();
- }
- while (running) {
- if (scape.isListenersAndMembersCurrent() && (!paused || step)) {
- scape.executeOnRoot(Scape.CLEAR_STATS_RULE);
- iteration++;
- period++;
- // I've moved the pausePeriod code here because when it was
- // located in runMainLoop() the
- // views were not getting properly updated when the pause period
- // was reached. - Mario
- if (period == getPausePeriod() && !paused) {
- pause();
- }
- scape.executeOnRoot(Scape.EXECUTE_RULES_RULE);
- scape.executeOnRoot(Scape.COLLECT_STATS_RULE);
- scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_ITERATE));
- step = false;
- } else {
- if (paused) {
- waitForViewsUpdate();
- scape.executeOnRoot(new NotifyViews(ScapeEvent.TICK));
- try {
- // Wait for user to unpause model
- Thread.sleep(100);
- } catch (InterruptedException e) {
- }
- } else {
- try {
- // Don't hog cycles while listeners are updating!
- Thread.sleep(10);
- } catch (InterruptedException e) {
- }
- }
- }
- if (period >= getStopPeriod()) {
- waitForViewsUpdate();
- running = false;
- if (isAutoRestart()) {
- restartRequested = true;
- }
- }
- if (closeAndOpenNewRequested) {
- new Thread(this, "Ascape Main Execution Loop") {
- public void run() {
- closeAndOpenNewFinally(scape);
- }
- }.start();
- closeAndOpenNewRequested = false;
- }
- if (closeAndOpenSavedRequested) {
- new Thread(this, "Ascape Main Execution Loop") {
- public void run() {
- closeAndOpenSavedFinally(scape);
- }
- }.start();
- closeAndOpenSavedRequested = false;
- }
- if (saveRequested) {
- waitForViewsUpdate();
- saveChoose();
- saveRequested = false;
- }
- if (openRequested) {
- waitForViewsUpdate();
- openChoose();
- openRequested = false;
- }
- }
- scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_STOP));
- // Wait to ensure that all listeners are notified
- waitForViewsUpdate();
- if (restartRequested) {
- // Send an event to self for start
- scape.respondControl(new ControlEvent(this, ControlEvent.REQUEST_START));
- }
- if (closeRequested) {
- closeFinally();
- closeRequested = false;
- }
- if (quitRequested) {
- quitFinally();
- }
- inMainLoop = false;
- }
-
- /**
- * Responds to any control events fired at this scape. Currently reacts to
- * start, stop, pause, resume, step, quit, and restart events, as well as
- * listener update report events. All control events except listener updates
- * are passed up to the root. Any other events trigger an untrapped
- * exception.
- */
- public void respondControl(ControlEvent control) {
- switch (control.getID()) {
- case ControlEvent.REQUEST_CLOSE:
- close();
- break;
- case ControlEvent.REQUEST_OPEN:
- closeAndOpenNew();
- break;
- case ControlEvent.REQUEST_OPEN_SAVED:
- closeAndOpenSaved();
- break;
- case ControlEvent.REQUEST_SAVE:
- save();
- break;
- case ControlEvent.REQUEST_START:
- start();
- break;
- case ControlEvent.REQUEST_STOP:
- stop();
- break;
- case ControlEvent.REQUEST_STEP:
- setStep(true);
- break;
- case ControlEvent.REQUEST_RESTART:
- restart();
- break;
- case ControlEvent.REQUEST_PAUSE:
- pause();
- break;
- case ControlEvent.REQUEST_RESUME:
- resume();
- break;
- case ControlEvent.REQUEST_QUIT:
- quit();
- break;
- default:
- throw new RuntimeException("Unknown control event sent to Agent scape: " + control + " [" + control.getID()
- + "]");
- }
- }
-
- /**
- * Blocks until all views of this scape and this scape's members have been
- * updated.
- */
- public void waitForViewsUpdate() {
- while (!scape.isAllViewsUpdated() && inMainLoop) {
- try {
- // Don't hog cycles while listeners are updating!
- Thread.sleep(10);
- } catch (InterruptedException e) {
- }
- }
- }
-
- /**
- * Requests the scape to open another model, closing the existing one. Will
- * not occur until the current iteration is complete; use static forms to
- * open concurrently. Always called on root.
- */
- public void closeAndOpenNew() {
- if (running) {
- // Running, so we have to allow current iteration to finish
- closeAndOpenNewRequested = true;
- } else {
- closeAndOpenNewFinally(scape);
- }
- }
-
- /**
- * Requests the scape to open a saved run, closing the existing one. Will
- * not occur until the current iteration is complete; use static forms to
- * open concurrently. Always called on root.
- */
- public void closeAndOpenSaved() {
- if (isRunning()) {
- // Running, so we have to allow current iteration to finish
- setCloseAndOpenNewRequested(true);
- } else {
- // have to start a new thread or else the GUI locks up
- new Thread(this) {
- public void run() {
- closeAndOpenSavedFinally(getRootScape());
- }
- }.start();
- }
- }
-
- /**
- * Requests the scape to open another model, closing the existing one.
- * Always called on root.
- */
- public void closeAndOpenNewFinally(final Scape oldScape) {
- boolean oldWasPaused = oldScape.isPaused();
- if (!oldWasPaused) {
- oldScape.getRunner().pause();
- }
- final String modelName = ((AbstractUIEnvironment) environment).openDialog();
- if (!oldWasPaused) {
- oldScape.getRunner().resume();
- }
- if (modelName != null) {
- // We want the old scape ot close first..
- oldScape.addView(new DefaultScapeListener() {
- /**
+ private static final long serialVersionUID = 6924379091134591724L;
+
+ private Scape scape;
+
+ /**
+ * Data group for all scapes. At some point this may be made non-static.
+ */
+ private DataGroup dataGroup;
+
+ /**
+ * Should any scapes opened be started automatically? Default true. true.
+ */
+ private static boolean startOnOpen = true;
+
+ /**
+ * Manages user space UI, settings etc.
+ */
+ protected transient RuntimeEnvironment environment;
+
+ /**
+ * The unit of time each iteration or period represents.
+ */
+ private String periodName = "Iteration";
+
+ /**
+ * A brief descripiton (including credits) of the scape or of the model, if
+ * this is root scape. Plaintext.
+ */
+ private String description;
+
+ /**
+ * A brief descripiton (including credits) of the scape or of the model, if
+ * this is root scape. Includes HTML style tags as appropriate.
+ */
+ private String HTMLDescription;
+
+ /**
+ * Iteration to start on when restarting, creating new model, etc...
+ */
+ private int startPeriod = 0;
+
+ /**
+ * Iteration to stop on.
+ */
+ private int stopPeriod = Integer.MAX_VALUE;
+
+ /**
+ * Period to pause on.
+ */
+ private int pausePeriod = Integer.MAX_VALUE;
+
+ /**
+ * The system path in which all files are by default stored to and retrieved
+ * from. The value of the system variable ascape home.
+ */
+ private String home;
+
+ /**
+ * The earliest period this scape is expected to be run at.
+ */
+ private int earliestPeriod;
+
+ /**
+ * The latest period this scape is expected to be run at.
+ */
+ private int latestPeriod = Integer.MAX_VALUE;
+
+ private List restartingViews = new Vector();
+
+ /**
+ * The number of iterations since the scape began iterating.
+ */
+ private int iteration;
+
+ /**
+ * The current period.
+ */
+ private int period;
+
+ /**
+ * Is the scape currently paused?
+ */
+ private boolean paused = false;
+
+ /**
+ * Is the scape currently running?
+ */
+ private boolean running = false;
+
+ /**
+ * Has a step been requested?
+ */
+ private boolean step = false;
+
+ /**
+ * Has a restart been requested after the current run stops?
+ */
+ private boolean closeAndOpenNewRequested = false;
+
+ /**
+ * Has loading of a saved run been requested after the current run stops?
+ */
+ private boolean closeAndOpenSavedRequested = false;
+
+ /*
+ * All of the following will be replaced by a diferred control mechanism.
+ */
+
+ /**
+ * Has a restart been requested after the current run stops?
+ */
+ private boolean restartRequested = false;
+
+ /**
+ * Has a close been requested after the current run stops?
+ */
+ private boolean closeRequested = false;
+
+ /**
+ * Has a quit been requested after the current run stops?
+ */
+ private boolean quitRequested = false;
+
+ /**
+ * Has an open been requested when the current iteration completes?
+ */
+ private boolean openRequested = false;
+
+ /**
+ * Has a save been requested when the current iteration completes?
+ */
+ private boolean saveRequested = false;
+
+ /**
+ * Are we currently in the main control loop?
+ */
+ private boolean inMainLoop = false;
+
+ private boolean beginningDeserializedRun = false;
+
+ /**
+ * Should the scape be restarted automatically after being stopped?
+ */
+ private boolean autoRestart = true;
+
+ /**
+ * Indicates that GUI should be displayed, if false, not GUI under any
+ * circumstances.
+ */
+ private static boolean displayGraphics = true;
+
+ /**
+ * Indicates that we are forwarding graphics to a client scape.
+ */
+ private static boolean serveGraphics = false;
+
+ /**
+ * Indicates that we are in a multiwin environment and want simple winsow
+ * strucutures.
+ */
+ private static boolean muiltWinEnvironment;
+
+ private Thread modelThread;
+
+ public Runner() {
+ this(new RuntimeEnvironment());
+ }
+
+ public Runner(RuntimeEnvironment environment) {
+ this.environment = environment;
+ }
+
+ protected void initialize() {
+ setInternalRunning(false);
+ getData().clear();
+ scape.reseed();
+ scape.execute(new NotifyViews(ScapeEvent.REQUEST_SETUP));
+ waitForViewsUpdate();
+ setIteration(0);
+ setPeriod(getStartPeriod());
+ scape.execute(Scape.INITIALIZE_RULE);
+ scape.execute(new NotifyViews(ScapeEvent.REPORT_INITIALIZED));
+ waitForViewsUpdate();
+ scape.execute(Scape.INITIAL_RULES_RULE);
+ setInternalRunning(true);
+ }
+
+ /**
+ * The main run loop of a running simulation. Seperated from run so that it
+ * can be executed in different runtime modes.
+ */
+ protected synchronized void runMainLoop() {
+ inMainLoop = true;
+ restartRequested = false;
+ if (beginningDeserializedRun) { // we are re-starting the main loop
+ // after reading in a serialized model
+ beginningDeserializedRun = false;
+ saveRequested = false;
+ initialize();
+ scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_DESERIALIZED));
+ waitForViewsUpdate();
+ scape.reseed();
+ getEnvironment().getConsole().println("\nNew Random Seed: " + scape.getRandomSeed() + "\n");
+ } else { // !beginningDeserializedRun
+ scape.executeOnRoot(Scape.CLEAR_STATS_RULE);
+ initialize();
+ scape.executeOnRoot(Scape.COLLECT_STATS_RULE);
+ scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_START));
+ waitForViewsUpdate();
+ }
+ while (running) {
+ if (scape.isListenersAndMembersCurrent() && (!paused || step)) {
+ scape.executeOnRoot(Scape.CLEAR_STATS_RULE);
+ iteration++;
+ period++;
+ // I've moved the pausePeriod code here because when it was
+ // located in runMainLoop() the
+ // views were not getting properly updated when the pause period
+ // was reached. - Mario
+ if (period == getPausePeriod() && !paused) {
+ pause();
+ }
+ scape.executeOnRoot(Scape.EXECUTE_RULES_RULE);
+ scape.executeOnRoot(Scape.COLLECT_STATS_RULE);
+ scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_ITERATE));
+ step = false;
+ } else {
+ if (paused) {
+ waitForViewsUpdate();
+ scape.executeOnRoot(new NotifyViews(ScapeEvent.TICK));
+ try {
+ // Wait for user to unpause model
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ } else {
+ try {
+ // Don't hog cycles while listeners are updating!
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ if (period >= getStopPeriod()) {
+ waitForViewsUpdate();
+ running = false;
+ if (isAutoRestart()) {
+ restartRequested = true;
+ }
+ }
+ if (closeAndOpenNewRequested) {
+ new Thread(this, "Ascape Main Execution Loop") {
+ public void run() {
+ closeAndOpenNewFinally(scape);
+ }
+ }.start();
+ closeAndOpenNewRequested = false;
+ }
+ if (closeAndOpenSavedRequested) {
+ new Thread(this, "Ascape Main Execution Loop") {
+ public void run() {
+ closeAndOpenSavedFinally(scape);
+ }
+ }.start();
+ closeAndOpenSavedRequested = false;
+ }
+ if (saveRequested) {
+ waitForViewsUpdate();
+ saveChoose();
+ saveRequested = false;
+ }
+ if (openRequested) {
+ waitForViewsUpdate();
+ openChoose();
+ openRequested = false;
+ }
+ }
+ scape.executeOnRoot(new NotifyViews(ScapeEvent.REPORT_STOP));
+ // Wait to ensure that all listeners are notified
+ waitForViewsUpdate();
+ if (restartRequested) {
+ // Send an event to self for start
+ scape.respondControl(new ControlEvent(this, ControlEvent.REQUEST_START));
+ }
+ if (closeRequested) {
+ closeFinally();
+ closeRequested = false;
+ }
+ if (quitRequested) {
+ quitFinally();
+ }
+ inMainLoop = false;
+ }
+
+ /**
+ * Responds to any control events fired at this scape. Currently reacts to
+ * start, stop, pause, resume, step, quit, and restart events, as well as
+ * listener update report events. All control events except listener updates
+ * are passed up to the root. Any other events trigger an untrapped exception.
+ */
+ public void respondControl(ControlEvent control) {
+ switch (control.getID()) {
+ case ControlEvent.REQUEST_CLOSE:
+ close();
+ break;
+ case ControlEvent.REQUEST_OPEN:
+ closeAndOpenNew();
+ break;
+ case ControlEvent.REQUEST_OPEN_SAVED:
+ closeAndOpenSaved();
+ break;
+ case ControlEvent.REQUEST_SAVE:
+ save();
+ break;
+ case ControlEvent.REQUEST_START:
+ start();
+ break;
+ case ControlEvent.REQUEST_STOP:
+ stop();
+ break;
+ case ControlEvent.REQUEST_STEP:
+ setStep(true);
+ break;
+ case ControlEvent.REQUEST_RESTART:
+ restart();
+ break;
+ case ControlEvent.REQUEST_PAUSE:
+ pause();
+ break;
+ case ControlEvent.REQUEST_RESUME:
+ resume();
+ break;
+ case ControlEvent.REQUEST_QUIT:
+ quit();
+ break;
+ default:
+ throw new RuntimeException("Unknown control event sent to Agent scape: " + control + " [" + control.getID() + "]");
+ }
+ }
+
+ /**
+ * Blocks until all views of this scape and this scape's members have been
+ * updated.
+ */
+ public void waitForViewsUpdate() {
+ while (!scape.isAllViewsUpdated() && inMainLoop) {
+ try {
+ // Don't hog cycles while listeners are updating!
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ /**
+ * Requests the scape to open another model, closing the existing one. Will
+ * not occur until the current iteration is complete; use static forms to open
+ * concurrently. Always called on root.
+ */
+ public void closeAndOpenNew() {
+ if (running) {
+ // Running, so we have to allow current iteration to finish
+ closeAndOpenNewRequested = true;
+ } else {
+ closeAndOpenNewFinally(scape);
+ }
+ }
+
+ /**
+ * Requests the scape to open a saved run, closing the existing one. Will not
+ * occur until the current iteration is complete; use static forms to open
+ * concurrently. Always called on root.
+ */
+ public void closeAndOpenSaved() {
+ if (isRunning()) {
+ // Running, so we have to allow current iteration to finish
+ setCloseAndOpenNewRequested(true);
+ } else {
+ // have to start a new thread or else the GUI locks up
+ new Thread(this) {
+ public void run() {
+ closeAndOpenSavedFinally(getRootScape());
+ }
+ }.start();
+ }
+ }
+
+ /**
+ * Requests the scape to open another model, closing the existing one. Always
+ * called on root.
+ */
+ public void closeAndOpenNewFinally(final Scape oldScape) {
+ boolean oldWasPaused = oldScape.isPaused();
+ if (!oldWasPaused) {
+ oldScape.getRunner().pause();
+ }
+ final String modelName = ((AbstractUIEnvironment) environment).openDialog();
+ if (!oldWasPaused) {
+ oldScape.getRunner().resume();
+ }
+ if (modelName != null) {
+ // We want the old scape ot close first..
+ oldScape.addView(new DefaultScapeListener() {
+ /**
*
*/
- private static final long serialVersionUID = 1L;
-
- public void scapeClosing(ScapeEvent scapeEvent) {
- openInstance(modelName);
- }
- });
- oldScape.getRunner().close();
- }
- }
-
- public static Scape openSavedRun(InputStream is) throws IOException {
- Scape newScape = null;
- GZIPInputStream gis = new GZIPInputStream(is);
- ObjectInputStream ois = new ObjectInputStream(gis);
-
- try {
- newScape = (Scape) ois.readObject();
- ois.close();
- // startPeriod is static so we have to set it here
- // we set it to scape.period + 1 so that there is not a blank first
- // point in the charts
- try {
- newScape.setStartPeriod(newScape.getPeriod() + 1);
- } catch (SpatialTemporalException e) {
- try {
- newScape.setStartPeriod(newScape.getPeriod());
- } catch (SpatialTemporalException e1) {
- try {
- newScape.setStartPeriod(newScape.getPeriod());
- } catch (SpatialTemporalException e2) {
- throw new RuntimeException("Internal Error");
- }
- }
- }
- newScape.getRunner().beginningDeserializedRun = true;
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return newScape;
- }
-
- public Scape openSavedRun(String fileName, String[] args) throws IOException {
- Scape newScape = openSavedRun(new File(fileName));
-
- if (newScape != null) {
-
- if (args.length > 0) {
- newScape.assignParameters(args, true);
- }
- newScape.getRunner().createEnvironment();
-
- if (newScape.isPaused() && newScape.isStartOnOpen()) {
- newScape.getRunner().resume();
- }
-
- newScape.getRunner().runMainLoop();
- }
-
- return newScape;
- }
-
- public Scape openSavedRun(File savedRunFile) throws IOException {
- Scape newScape = null;
- InputStream is = new FileInputStream(savedRunFile);
- newScape = openSavedRun(is);
- return newScape;
- }
-
- // public void createNewModel() {
- // createNewModel(null, new String[0]);
- // }
- //
- // public void createNewModel(Object applet, String[] args) {
- // try {
- // if (applet != null) {
- // scape.getUIEnvironment().setApplet(applet, scape);
- // }
- // if (args != null) {
- // // first pass of parseSettingArgs,
- // // don't report any parameters not found
- // scape.assignParameters(args, false);
- // }
- // scape.executeOnRoot(Scape.CREATE_RULE);
- // if (args != null) {
- // // second pass of parseSettingArgs,
- // // this time report any parameters not found
- // scape.assignParameters(args, true);
- // }
- // // mtp 12/7/2000
- // scape.executeOnRoot(Scape.CREATE_VIEW_RULE);
- // if (Runner.isStartOnOpen()) {
- // start();
- // }
- // } catch (RuntimeException e) {
- // if (scape.getUIEnvironment() != null) {
- // scape.getUIEnvironment().showErrorDialog(scape, e);
- // } else {
- // throw (e);
- // }
- // }
- // }
-
- /**
- * Open (create) and run the model, just as in the normal open, but block
- * execution. Should be used for testing model run behavior only.
- */
- public void testRun() {
- try {
- scape.executeOnRoot(Scape.CREATE_RULE);
- run();
- } catch (RuntimeException e) {
- if (scape.getUIEnvironment() != null) {
- scape.getUIEnvironment().showErrorDialog(scape, e);
- } else {
- throw e;
- }
- }
- }
-
- /**
- * Requests the scape to save itself, providing UI for this purpose. Will
- * not occur until the current iteration is complete. Always called on root.
- */
- public void save() {
- if (scape.isRoot()) {
- saveRequested = true;
- } else {
- save();
- }
- }
-
- /**
- * The basic execution cycle of a running scape. In normal usage this method
- * is not called directly; use start() instead. You might choose to call
- * this method directly if you want the calling code to block, for instance,
- * in order to test that some behavior occurs. In the current
- * implementation, only the root scape is a running thread; all child scapes
- * are iterated through the root thread. Synchronous, determined,
- * reproducible behavior is expected, let us know if you encounter anything
- * different! The cycle always begins by notifying any observers, giving
- * them a chance to observe initial state. Then, the scape waits for the
- * observers to update. When updated, the simulation iterates the root scape
- * and all child scapes with their rules. Again, the scape waits for the
- * observers to update, and the cycle of iteration and update continues
- * until it is paused or stopped. While paused, tick events will be sent to
- * observers, which typically chose to ignore them.
- */
- public synchronized void run() {
- run(false);
- }
-
- /**
- * Sets values for the models paramters based on supplied array of key value
- * pairs. Paramters and values are expected to be seperated with an "=", for
- * example: "MyParameter=12".
- *
- * @param args
- * an array of strings with paramter-value paris in the form
- * "{paramter-name}={paramter-value}"
- * @param reportNotFound
- * if paramters not found should result in a console notification
- * and if errors in invocation should be reported, false
- * otherwise
- */
- public static boolean assignEnvironmentParameters(String[] args) {
- boolean found = args.length == 0;
- for (String arg : args) {
- String paramName = PropertyAccessor.paramName(arg);
- found = found || assignEnvironmentParameter(arg, paramName);
- }
- return found;
- }
-
- public static boolean assignEnvironmentParameter(String arg, String paramName) {
- boolean found = false;
- if (paramName != null) {
- if (paramName.equalsIgnoreCase("DisplayGraphics")) {
- Runner.setDisplayGraphics(PropertyAccessor.paramValueBoolean(arg));
- found = true;
- } else if (paramName.equalsIgnoreCase("ServeGraphics")) {
- Runner.setServeGraphics(PropertyAccessor.paramValueBoolean(arg));
- found = true;
- } else if (paramName.equalsIgnoreCase("MultiWin")) {
- Runner.setMultiWinEnvironment(PropertyAccessor.paramValueBoolean(arg));
- found = true;
- } else if (paramName.equalsIgnoreCase("RedirectConsole")) {
- AbstractUIEnvironment.setRedirectConsole(PropertyAccessor.paramValueBoolean(arg));
- found = true;
- } else if (paramName.equalsIgnoreCase("ShowNavigator")) {
- AbstractUIEnvironment.setShowNavigator(PropertyAccessor.paramValueBoolean(arg));
- found = true;
- }
- // if (!found && reportNotFound) {
- // getEnvironment().getConsole().println("***WARNING: Parameter not found: " + paramName);
- // }
- }
- return found;
- }
-
- public void launch(String[] args) throws IOException {
- if (args.length > 0 && args[0].indexOf("=") == -1) {
- assignEnvironmentParameters(args);
- // the first arg is not a "key=value" pair, so it must be the
- // name of a java class implementing an Ascape model
- String[] argsRem = new String[args.length - 1];
- System.arraycopy(args, 1, argsRem, 0, argsRem.length);
- open(args[0], argsRem);
- } else {
- String fileName = null;
- List argsList = new LinkedList(Arrays.asList(args));
-
- for (ListIterator li = argsList.listIterator(); li.hasNext();) {
- String arg = (String) li.next();
- int equalAt = arg.lastIndexOf("=");
- if (equalAt < 1) {
- getEnvironment().getConsole().println("Syntax error in command line: " + arg);
- } else {
- String paramName = arg.substring(0, equalAt);
- if (paramName.equalsIgnoreCase("SavedRun")) {
- fileName = arg.substring(equalAt + 1);
- li.remove();
- }
- }
- }
- if (fileName != null) {
- scape = openSavedRun(fileName, (String[]) argsList.toArray(new String[0]));
- } else {
- // moved to top of method, so the license agreement has a frame
- // environment = new UIEnvironment();
- // OK to do this here, since we know the user has to be in a GUI
- // environment (don't have to wait to assign params...
- // environment = new UIEnvironment();
- // UIEnvironment.checkForLicenseAgreement();
- scape = openChoose(args);
- if (scape != null) {
- scape.getRunner().createEnvironment();
- } else {
- System.exit(0);
- }
- }
- }
- }
-
- /**
- * The basic execution cycle of a running scape. In normal usage this methos
- * is not called directly; use start() instead. You might choose to call
- * this method directly if you want the calling code to block, for instance,
- * in order to test that some behavior occurs. Also use this version with
- * argument "true" if you want to continue using the same thread for
- * restarts.
- *
- * @param singlethread
- * CURRENTLY IGNORED! should the run if restarted continue to use the same thread?
- */
- public void run(boolean singlethread) {
- if (scape.getUIEnvironment() != null
- && scape.getUIEnvironment().getRuntimeMode() == AbstractUIEnvironment.RELEASE_RUNTIME_MODE) {
- try {
- runMainLoop();
- } catch (RuntimeException e) {
- scape.getUIEnvironment().showErrorDialog(scape, e);
- }
- } else {
- runMainLoop();
- }
- }
-
- /**
- * Requests the scape to start. Note that the scape may not start
- * immeadiatly.
- *
- * @see #setRunning
- */
- public void start() {
- if (!isRunning()) {
- modelThread = new Thread(this, "Ascape Main Execution Loop");
- modelThread.start();
- } else {
- System.out.println("Warning: Tried to start an already running scape.");
- }
- }
-
- public void notify(final ScapeEvent event, final ScapeListener listener) {
- listener.scapeNotification(event);
- }
-
- public void write(final java.io.ObjectOutputStream out) throws IOException {
- out.defaultWriteObject();
- }
-
- /**
- * Requests the scape to stop. Note that the scape will not actually stop
- * until the current iteration is complete.
- *
- * @see #setRunning
- */
- public void stop() {
- setInternalRunning(false);
- }
-
- /**
- * Requests the scape to pause. (Convenience method).
- *
- * @see #setPaused
- */
- public void pause() {
- setPaused(true);
- }
-
- /**
- * Requests the scape to resume. (Convenience method).
- *
- * @see #setPaused
- */
- public void resume() {
- setPaused(false);
- }
-
- /**
- * Requests the scape to restart.
- */
- public void requestRestart() {
- restartRequested = true;
- }
-
- /**
- * Stops the scape and requests the scape to restart. (Convenience method).
- *
- * @see #setRunning
- */
- public void restart() {
- if (running) {
- stop();
- restartRequested = true;
- } else {
- start();
- }
- }
-
- /**
- * Method neccessary because of amibiguous null values in simpler signature
- * methods.
- */
- public void openImplementation(String[] args, boolean block) {
- try {
- if (args != null) {
- // first pass of parseSettingArgs,
- // don't report any parameters not found
- scape.assignParameters(args, false);
- }
- scape.executeOnRoot(Scape.CREATE_RULE);
- if (args != null) {
- // second pass of parseSettingArgs,
- // this time report any parameters not found
- scape.assignParameters(args, true);
- }
- if (scape.getEnvironment() != null) {
- scape.addView(scape.getEnvironment());
- }
-
- scape.executeOnRoot(Scape.CREATE_VIEW_RULE);
- scape.createViews(args);
-
- if (Runner.isStartOnOpen()) {
- if (!block) {
- start();
- } else {
- run();
- }
- }
- } catch (RuntimeException e) {
- if (getEnvironment() instanceof AbstractUIEnvironment) {
- ((AbstractUIEnvironment) getEnvironment()).showErrorDialog(scape, e);
- } else {
- throw e;
- }
- }
- }
-
- /**
- * Creates and runs (if start on open is true) this model scape.
- *
- * @param applet
- * the applet if are we in an applet vm context
- * @param args
- * paramter arguments for the scape
- * @param block
- * should this call block or run in a new thread?
- */
- public void open(Object applet, String[] args, boolean block) {
- openImplementation(args, block);
- }
-
- /**
- * Creates and runs (if start on open is true) this model scape.
- *
- * @param applet
- * the applet if are we in an applet vm context
- * @param args
- * paramter arguments for the scape
- */
- public void open(Object applet, String[] args) {
- openImplementation(args, false);
- }
-
- /**
- * Creates and runs (if start on open is true) this model scape.
- *
- * @param args
- * paramter arguments for the scape
- * @param block
- * should this call block or run in a new thread?
- */
- public void open(String[] args, boolean block) {
- openImplementation(args, block);
- }
-
- /**
- * Creates and runs (if start on open is true) this model scape.
- *
- * @param args
- * paramter arguments for the scape
- */
- public void open(String[] args) {
- openImplementation(args, false);
- }
-
- /**
- * Creates and runs (if start on open is true) this model scape.
- */
- public void open() {
- openImplementation(null, false);
- }
-
- /**
- * Creates and runs (if start on open is true) this model scape.
- *
- * @param block
- * should this call block or run in a new thread?
- */
- public void open(boolean block) {
- openImplementation(null, block);
- }
-
- /**
- * Requests the scape to open a saved run.
- */
- public void openSavedChoose() {
- closeAndOpenSavedFinally(null);
- }
-
- public abstract void closeAndOpenSavedFinally(Scape oldScape);
-
-
- public Object instanceFromName(String modelName) {
- Object newObject;
- try {
- newObject = Thread.currentThread().getContextClassLoader().loadClass(modelName).newInstance();
- } catch (NullPointerException e) {
- throw new RuntimeException("An error ocurred while attempting to read " + modelName + ": " + e.getMessage(), e);
- } catch (InstantiationException e) {
- throw new RuntimeException("An error ocurred while attempting to read " + modelName + ": " + e.getMessage(), e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("An error ocurred while attempting to read " + modelName + ": " + e.getMessage(), e);
- } catch (ClassNotFoundException e) {
- try {
- Class c = Class.forName(modelName);
- newObject = c.newInstance();
- } catch (Exception e2) {
- throw new RuntimeException("Couldn't find class: " + modelName);
- }
- }
- return newObject;
- }
-
- /**
- * Constructs, creates and runs (if start on open is true) the supplied model.
- *
- * @deprecated Applets are no longer executed this way
- * @param modelName
- * the fully qualified name of the Java class for the model's root scape
- * @param applet
- * the applet if are we in an applet vm context
- * @param args
- * paramter arguments for the scape
- * @param block
- * should this call block or run in a new thread?
- */
- public Scape open(String modelName, Object applet, String[] args, boolean block) {
- return open(modelName, args, block);
- }
-
- /**
- * Constructs, creates and runs the supplied model.
- *
- * @param modelName
- * the fully qualified name of the Java class for the model's root scape
- * @param args
- * paramter arguments for the scape
- */
- public Scape open(String modelName, String[] args) {
- return open(modelName, args, false);
- }
-
- /**
- * Constructs, creates and runs the supplied model.
- *
- * @param modelName
- * the fully qualified name of the Java class for the model's
- * root scape
- * @param args
- * paramter arguments for the scape
- * @param block
- * should this call block or run in a new thread?
- */
- public Scape open(String modelName, String[] args, boolean block) {
-
- Scape newAgent = (Scape) instanceFromName(modelName);
- setRootScape(newAgent);
- open(args, block);
- return getRootScape();
- }
-
- /**
- * Constructs, creates and runs the supplied model.
- *
- * @deprecated Applets are no longer executed this way
- * @param modelName
- * the fully qualified name of the Java class for the model's root scape
- * @param applet
- * the applet if are we in an applet vm context
- */
- public Scape open(String modelName, Object applet) {
- return open(modelName, null, null, false);
- }
-
- /**
- * Constructs, creates and runs the supplied model.
- *
- * @param modelName
- * the fully qualified name of the Java class for the model's
- * root scape
- */
- public Scape open(String modelName, boolean block) {
- return open(modelName, null, null, block);
- }
-
- /**
- * Constructs, creates and runs the supplied model.
- *
- * @param modelName
- * the fully qualified name of the Java class for the model's
- * root scape
- */
- public Scape openInstance(String modelName) {
- return open(modelName, null, new String[0], false);
- }
-
- /**
- * Requests the scape to open a model, providing UI for this purpose.
- */
- public Scape openChoose() {
- return openChoose(null);
- }
-
- /**
- * Requests the scape to open a model, providing UI for this purpose.
- */
- public Scape openChoose(String[] args) {
- String modelName = ((AbstractUIEnvironment) environment).openDialog();
- Scape scape = null;
- if (modelName != null) {
- scape = open(modelName, args);
- }
- return scape;
- }
-
- /*
- * To be done (perhaps) Opens the specified scape from a class file.
- */
- /*
- * public static void open(File file) { FileInputStream f = new
- * FileInputStream(file); ObjectInputStream s = new ObjectInputStream(f);
- * try { Scape newScape = (Scape) s.readObject(); } catch
- * (ClassNotFoundException e) { JOptionPane.showMessageDialog(null, "A class
- * couldn't be found (make sure you have all the appropriate model classes
- * installed): " + e, "Error", JOptionPane.INFORMATION_MESSAGE); } }
- */
-
- /**
- * Save the state of the scape to a file.
- */
- public abstract void saveChoose();
-
- public void close() {
- closeRequested = true;
- if (running) {
- // Running, so we have to allow current iteration to finish
- stop();
- } else {
- closeFinally();
- }
- }
-
- /**
- * Closes the application; allowing views to close themseleves gracefully.
- * Do not call this method directly unless you want to force close; call
- * <code>close()</code> instead, allowing a running scape to stop
- * gracefully. Override this method if you want to provide any scape related
- * pre-quit finalization or clean-up.
- *
- * @see #quit
- */
- public void closeFinally() {
- dataGroup = null;
- // Send an event to self for quit
- scape.executeOnRoot(new NotifyViews(ScapeEvent.REQUEST_CLOSE));
- waitForViewsUpdate();
- }
-
- /**
- * Exits the application; calling stop if running and allowing views to
- * close themseleves gracefully. Override <code>quitFinally</code> if you
- * want to provide any pre-quit finalization or clean-up.
- *
- * @see #quitFinally
- */
- public void quit() {
- if (inMainLoop) {
- quitRequested = true;
- // Running, so we have to allow current iteration to finish
- stop();
- }
- // Only one chance a quit request, otherwise we assume that the scape is
- // allready fulfilling it.
- else if (!quitRequested) {
- quitFinally();
- }
- }
-
- /**
- * Exits the application; allowing views to close themseleves gracefully. Do
- * not call this method directly unless you want to force quit; call
- * <code>quit()</code> instead, allowing a running scape to stop
- * gracefully. Override this method if you want to provide any scape related
- * pre-quit finalization or clean-up.
- *
- * @see #quit
- */
- public void quitFinally() {
- closeFinally();
- scape.executeOnRoot(new NotifyViews(ScapeEvent.REQUEST_QUIT));
- waitForViewsUpdate();
- exit();
- }
-
- /**
- * Final kill. Calls System exit, which appears neccessary for vm even when
- * code has finished.
- */
- public static void exit() {
- try {
- System.exit(0);
- } catch (SecurityException e) {
- System.out
- .println("Can't quit in this security context. (Scape is probably running in browser or viewer; quit or change that.)");
- }
- }
-
- public void createEnvironment() {
- if (environment == null) {
- environment = new RuntimeEnvironment();
- }
- }
-
- public static boolean isDisplayGraphics() {
- try {
- return displayGraphics && !GraphicsEnvironment.isHeadless();
- } catch (HeadlessException e) {
- return false;
- }
- }
-
- public static void setDisplayGraphics(boolean displayGraphics) {
- Runner.displayGraphics = displayGraphics;
- }
-
- public static boolean isServeGraphics() {
- return serveGraphics;
- }
-
- public static void setServeGraphics(boolean serveGraphics) {
- Runner.serveGraphics = serveGraphics;
- }
-
- public static boolean isMultiWinEnvironment() {
- return muiltWinEnvironment;
- }
-
- public static void setMultiWinEnvironment(boolean muiltWinEnvironment) {
- Runner.muiltWinEnvironment = muiltWinEnvironment;
- }
-
- /**
- * Sets the period name for the delegate
- *
- * @return the periodName
- */
- public String getPeriodName() {
- return periodName;
- }
-
- /**
- * Sets periodName for the ModelRoot object.
- *
- * @param periodName
- * the periodName
- */
- public void setPeriodName(String periodName) {
- this.periodName = periodName;
- }
-
- /**
- * Gets the description for the ModelRoot object.
- *
- * @return the description
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * Sets description for the ModelRoot object.
- *
- * @param description
- * the description
- */
- public void setDescription(String description) {
- this.description = description;
- }
-
- /**
- * Returns a brief descripiton (including credits) of the scape or of the
- * model, if this is root scape. Plaintext.
- *
- * @return the description
- */
- public String getHTMLDescription() {
- return HTMLDescription;
- }
-
- /**
- * Sets an html-formatted description to be used for the model as a whole.
- *
- * @param HTMLdescription
- * the description
- */
- public void setHTMLDescription(String HTMLdescription) {
- this.HTMLDescription = HTMLdescription;
- }
-
- /**
- * Returns the period that this model started.
- *
- * @return the startPeriod
- */
- public int getStartPeriod() {
- return startPeriod;
- }
-
- /**
- * Gets the startOnOpen for the Runner object. Start on Open is static
- * because we may not have a scape context.
- *
- * @return the startOnOpen
- */
- public static boolean isStartOnOpen() {
- return startOnOpen;
- }
-
- /**
- * Sets startOnOpen for the ModelRoot object.
- *
- * @param startOnOpen
- * the startOnOpen
- */
- public static void setStartOnOpen(boolean _startOnOpen) {
- startOnOpen = _startOnOpen;
- }
-
- /**
- * Sets the start period for this scape. The start period is the period this
- * scape is given when a model run is started.
- *
- * @param startPeriod
- * the period to begin runs at
- * @throws org.ascape.model.space.SpatialTemporalException
- * exception
- */
- public void setStartPeriod(int startPeriod) throws SpatialTemporalException {
- if (startPeriod >= earliestPeriod) {
- this.startPeriod = startPeriod;
- } else {
- throw new SpatialTemporalException("Tried to set start period before earliest period");
- }
- }
-
- /**
- * Returns the period this scape stops running at. By default, the lesser of
- * latest period and integer maximum value (effectively unlimited.)
- *
- * @return the stopPeriod
- */
- public int getStopPeriod() {
- return stopPeriod;
- }
-
- /**
- * Sets the stop period for this scape. The stop period is the period that
- * the scape is automatically stopped at. The scape may be automatically set
- * to start agina at start value is the scape is set to restart.
- *
- * @param stopPeriod
- * the period the scape will stop at upon reaching
- * @see #setAutoRestart
- * @throws org.ascape.model.space.SpatialTemporalException
- * exception
- */
- public void setStopPeriod(int stopPeriod) throws SpatialTemporalException {
- if (stopPeriod <= latestPeriod) {
- this.stopPeriod = stopPeriod;
- } else {
- throw new SpatialTemporalException("Tried to set stop period after latest period");
- }
- }
-
- /**
- * Gets the pausePeriod for the ModelRoot object.
- *
- * @return the pausePeriod
- */
- public int getPausePeriod() {
- return pausePeriod;
- }
-
- /**
- * Sets pausePeriod for the ModelRoot object.
- *
- * @param pausePeriod
- * the pausePeriod
- */
- public void setPausePeriod(int pausePeriod) {
- this.pausePeriod = pausePeriod;
- }
-
- /**
- * Gets the earliestPeriod for the ModelRoot object.
- *
- * @return the earliestPeriod
- */
- public int getEarliestPeriod() {
- return earliestPeriod;
- }
-
- /**
- * Sets the earliest period this scape is expected to be run at. 0 by
- * default.
- *
- * @param earliestPeriod
- * the lowest period value this scape can have
- */
- public void setEarliestPeriod(int earliestPeriod) {
- this.earliestPeriod = earliestPeriod;
- if (startPeriod < earliestPeriod) {
- try {
- setStartPeriod(earliestPeriod);
- }
- // "Can't" happen
- catch (SpatialTemporalException e) {
- throw new RuntimeException("Internal Logic Error");
- }
- }
- }
-
- /**
- * Gets the latestPeriod for the ModelRoot object.
- *
- * @return the latestPeriod
- */
- public int getLatestPeriod() {
- return latestPeriod;
- }
-
- /**
- * Sets the latest period this scape is expected to be run at. Max of
- * integer (effectively unlimited) by default.
- *
- * @param latestPeriod
- * the highest period value this scape can have
- */
- public void setLatestPeriod(int latestPeriod) {
- this.latestPeriod = latestPeriod;
- if (stopPeriod > latestPeriod) {
- try {
- setStopPeriod(latestPeriod);
- }
- // "Can't" happen
- catch (SpatialTemporalException e) {
- throw new RuntimeException("Internal Logic Error");
- }
- }
- }
-
- /**
- * Gets the restartingViews for the ModelRoot object.
- *
- * @return the restartingViews
- */
- public List getRestartingViews() {
- return restartingViews;
- }
-
- /**
- * Sets restartingViews for the ModelRoot object.
- *
- * @param restartingViews
- * the restartingViews
- */
- public void setRestartingViews(List restartingViews) {
- this.restartingViews = restartingViews;
- }
-
- /**
- * Gets the AutoRestart for the ModelRoot object.
- *
- * @return the Restart state
- */
- public boolean isAutoRestart() {
- return autoRestart;
- }
-
- /**
- * Sets Restart for the ModelRoot object.
- *
- * @param autoRestart
- * should the model restart when it ends?
- */
- public void setAutoRestart(boolean autoRestart) {
- this.autoRestart = autoRestart;
- }
-
- /**
- * Is the supplied period a valid period for this scape?
- *
- * @param period
- * the period to test
- * @return true if within earliest and latest periods, false otherwise
- */
- public boolean isValidPeriod(int period) {
- return period >= earliestPeriod && period <= latestPeriod;
- }
-
- /**
- * Returns the path in which all files should by default be stored to and
- * retrieved from. Nonstatic, so that parameter can automatically be set
- * from command line, but backing variable is static. Default is "./", can
- * be modified by calling setHome or providing an ascape.home java property.
- * (This may change now since it is no longer neccesary.)
- *
- * @return the home
- */
- public String getHome() {
- if (home == null) {
- home = "./";
- try {
- home = System.getProperty("ascape.home", home);
- }
- // Ignore security exception; we may be running in an environment
- // such as an applet where we can't get ascape home
- // no probel,m we just need to make sure that lib, etc. are in the
- // right place.
- catch (SecurityException e) {
- }
- }
- return home;
- }
-
- /**
- * Sets the path in which to store all scape related files. Nonstatic, so
- * that parameter can automatically be set from command line, but backing
- * variable is static.
- *
- * @param home
- * the home
- */
- public void setHome(String home) {
- this.home = home;
- }
-
- public RuntimeEnvironment getEnvironment() {
- return environment;
- }
-
- public boolean isBeginningDeserializedRun() {
- return beginningDeserializedRun;
- }
-
- public void setBeginningDeserializedRun(boolean beginningDeserializedRun) {
- this.beginningDeserializedRun = beginningDeserializedRun;
- }
-
- public boolean isCloseAndOpenNewRequested() {
- return closeAndOpenNewRequested;
- }
-
- public void setCloseAndOpenNewRequested(boolean closeAndOpenNewRequested) {
- this.closeAndOpenNewRequested = closeAndOpenNewRequested;
- }
-
- public boolean isCloseAndOpenSavedRequested() {
- return closeAndOpenSavedRequested;
- }
-
- public void setCloseAndOpenSavedRequested(boolean closeAndOpenSavedRequested) {
- this.closeAndOpenSavedRequested = closeAndOpenSavedRequested;
- }
-
- public boolean isCloseRequested() {
- return closeRequested;
- }
-
- public void setCloseRequested(boolean closeRequested) {
- this.closeRequested = closeRequested;
- }
-
- public boolean isInMainLoop() {
- return inMainLoop;
- }
-
- public void setInMainLoop(boolean inMainLoop) {
- this.inMainLoop = inMainLoop;
- }
-
- public int getIteration() {
- return iteration;
- }
-
- public void setIteration(int iteration) {
- this.iteration = iteration;
- }
-
- public boolean isOpenRequested() {
- return openRequested;
- }
-
- public void setOpenRequested(boolean openRequested) {
- this.openRequested = openRequested;
- }
-
- public boolean isPaused() {
- return paused;
- }
-
- public void setPaused(boolean paused) {
- this.paused = paused;
- }
-
- public int getPeriod() {
- return period;
- }
-
- public void setPeriod(int period) {
- this.period = period;
- }
-
- public boolean isQuitRequested() {
- return quitRequested;
- }
-
- public void setQuitRequested(boolean quitRequested) {
- this.quitRequested = quitRequested;
- }
-
- public boolean isRestartRequested() {
- return restartRequested;
- }
-
- public void setRestartRequested(boolean restartRequested) {
- this.restartRequested = restartRequested;
- }
-
- public boolean isRunning() {
- return running;
- }
-
- public void setRunning(boolean running) {
- if (running) {
- start();
- } else {
- stop();
- }
- }
-
- public void setInternalRunning(boolean running) {
- this.running = running;
- }
-
- public boolean isSaveRequested() {
- return saveRequested;
- }
-
- public void setSaveRequested(boolean saveRequested) {
- this.saveRequested = saveRequested;
- }
-
- public boolean isStep() {
- return step;
- }
-
- public void setStep(boolean step) {
- this.step = step;
- }
-
- public DataGroup getData() {
- return dataGroup;
- }
-
- public void setRootScape(Scape scape) {
- this.scape = scape;
- scape.setRunner(this);
- dataGroup = new DataGroup();
- dataGroup.setScape(scape);
- }
-
- public Scape getRootScape() {
- return scape;
- }
-
- public void setEnvironment(RuntimeEnvironment environment) {
- this.environment = environment;
- }
-
- public Thread getModelThread() {
- return modelThread;
- }
+ private static final long serialVersionUID = 1L;
+
+ public void scapeClosing(ScapeEvent scapeEvent) {
+ openInstance(modelName);
+ }
+ });
+ oldScape.getRunner().close();
+ }
+ }
+
+ public static Scape openSavedRun(InputStream is) throws IOException {
+ Scape newScape = null;
+ GZIPInputStream gis = new GZIPInputStream(is);
+ ObjectInputStream ois = new ObjectInputStream(gis);
+
+ try {
+ newScape = (Scape) ois.readObject();
+ ois.close();
+ // startPeriod is static so we have to set it here
+ // we set it to scape.period + 1 so that there is not a blank first
+ // point in the charts
+ try {
+ newScape.setStartPeriod(newScape.getPeriod() + 1);
+ } catch (SpatialTemporalException e) {
+ try {
+ newScape.setStartPeriod(newScape.getPeriod());
+ } catch (SpatialTemporalException e1) {
+ try {
+ newScape.setStartPeriod(newScape.getPeriod());
+ } catch (SpatialTemporalException e2) {
+ throw new RuntimeException("Internal Error");
+ }
+ }
+ }
+ newScape.getRunner().beginningDeserializedRun = true;
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return newScape;
+ }
+
+ public Scape openSavedRun(String fileName, String[] args) throws IOException {
+ Scape newScape = openSavedRun(new File(fileName));
+
+ if (newScape != null) {
+
+ if (args.length > 0) {
+ newScape.assignParameters(args, true);
+ }
+ newScape.getRunner().createEnvironment();
+
+ if (newScape.isPaused() && newScape.isStartOnOpen()) {
+ newScape.getRunner().resume();
+ }
+
+ newScape.getRunner().runMainLoop();
+ }
+
+ return newScape;
+ }
+
+ public Scape openSavedRun(File savedRunFile) throws IOException {
+ Scape newScape = null;
+ InputStream is = new FileInputStream(savedRunFile);
+ newScape = openSavedRun(is);
+ return newScape;
+ }
+
+ // public void createNewModel() {
+ // createNewModel(null, new String[0]);
+ // }
+ //
+ // public void createNewModel(Object applet, String[] args) {
+ // try {
+ // if (applet != null) {
+ // scape.getUIEnvironment().setApplet(applet, scape);
+ // }
+ // if (args != null) {
+ // // first pass of parseSettingArgs,
+ // // don't report any parameters not found
+ // scape.assignParameters(args, false);
+ // }
+ // scape.executeOnRoot(Scape.CREATE_RULE);
+ // if (args != null) {
+ // // second pass of parseSettingArgs,
+ // // this time report any parameters not found
+ // scape.assignParameters(args, true);
+ // }
+ // // mtp 12/7/2000
+ // scape.executeOnRoot(Scape.CREATE_VIEW_RULE);
+ // if (Runner.isStartOnOpen()) {
+ // start();
+ // }
+ // } catch (RuntimeException e) {
+ // if (scape.getUIEnvironment() != null) {
+ // scape.getUIEnvironment().showErrorDialog(scape, e);
+ // } else {
+ // throw (e);
+ // }
+ // }
+ // }
+
+ /**
+ * Open (create) and run the model, just as in the normal open, but block
+ * execution. Should be used for testing model run behavior only.
+ */
+ public void testRun() {
+ try {
+ scape.executeOnRoot(Scape.CREATE_RULE);
+ run();
+ } catch (RuntimeException e) {
+ if (scape.getUIEnvironment() != null) {
+ scape.getUIEnvironment().showErrorDialog(scape, e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Requests the scape to save itself, providing UI for this purpose. Will not
+ * occur until the current iteration is complete. Always called on root.
+ */
+ public void save() {
+ if (scape.isRoot()) {
+ saveRequested = true;
+ } else {
+ save();
+ }
+ }
+
+ /**
+ * The basic execution cycle of a running scape. In normal usage this method
+ * is not called directly; use start() instead. You might choose to call this
+ * method directly if you want the calling code to block, for instance, in
+ * order to test that some behavior occurs. In the current implementation,
+ * only the root scape is a running thread; all child scapes are iterated
+ * through the root thread. Synchronous, determined, reproducible behavior is
+ * expected, let us know if you encounter anything different! The cycle always
+ * begins by notifying any observers, giving them a chance to observe initial
+ * state. Then, the scape waits for the observers to update. When updated, the
+ * simulation iterates the root scape and all child scapes with their rules.
+ * Again, the scape waits for the observers to update, and the cycle of
+ * iteration and update continues until it is paused or stopped. While paused,
+ * tick events will be sent to observers, which typically chose to ignore
+ * them.
+ */
+ public synchronized void run() {
+ run(false);
+ }
+
+ /**
+ * Sets values for the models paramters based on supplied array of key value
+ * pairs. Paramters and values are expected to be seperated with an "=", for
+ * example: "MyParameter=12".
+ *
+ * @param args
+ * an array of strings with paramter-value paris in the form
+ * "{paramter-name}={paramter-value}"
+ * @param reportNotFound
+ * if paramters not found should result in a console notification and
+ * if errors in invocation should be reported, false otherwise
+ */
+ public static boolean assignEnvironmentParameters(String[] args) {
+ boolean found = args.length == 0;
+ for (String arg : args) {
+ String paramName = PropertyAccessor.paramName(arg);
+ found = found || assignEnvironmentParameter(arg, paramName);
+ }
+ return found;
+ }
+
+ public static boolean assignEnvironmentParameter(String arg, String paramName) {
+ boolean found = false;
+ if (paramName != null) {
+ if (paramName.equalsIgnoreCase("DisplayGraphics")) {
+ Runner.setDisplayGraphics(PropertyAccessor.paramValueBoolean(arg));
+ found = true;
+ } else if (paramName.equalsIgnoreCase("ServeGraphics")) {
+ Runner.setServeGraphics(PropertyAccessor.paramValueBoolean(arg));
+ found = true;
+ } else if (paramName.equalsIgnoreCase("MultiWin")) {
+ Runner.setMultiWinEnvironment(PropertyAccessor.paramValueBoolean(arg));
+ found = true;
+ } else if (paramName.equalsIgnoreCase("RedirectConsole")) {
+ AbstractUIEnvironment.setRedirectConsole(PropertyAccessor.paramValueBoolean(arg));
+ found = true;
+ } else if (paramName.equalsIgnoreCase("ShowNavigator")) {
+ AbstractUIEnvironment.setShowNavigator(PropertyAccessor.paramValueBoolean(arg));
+ found = true;
+ }
+ // if (!found && reportNotFound) {
+ // getEnvironment().getConsole().println("***WARNING: Parameter not found: "
+ // + paramName);
+ // }
+ }
+ return found;
+ }
+
+ public void launch(String[] args) throws IOException {
+ if (args.length > 0 && args[0].indexOf("=") == -1) {
+ assignEnvironmentParameters(args);
+ // the first arg is not a "key=value" pair, so it must be the
+ // name of a java class implementing an Ascape model
+ String[] argsRem = new String[args.length - 1];
+ System.arraycopy(args, 1, argsRem, 0, argsRem.length);
+ open(args[0], argsRem);
+ } else {
+ String fileName = null;
+ List argsList = new LinkedList(Arrays.asList(args));
+
+ for (ListIterator li = argsList.listIterator(); li.hasNext();) {
+ String arg = (String) li.next();
+ int equalAt = arg.lastIndexOf("=");
+ if (equalAt < 1) {
+ getEnvironment().getConsole().println("Syntax error in command line: " + arg);
+ } else {
+ String paramName = arg.substring(0, equalAt);
+ if (paramName.equalsIgnoreCase("SavedRun")) {
+ fileName = arg.substring(equalAt + 1);
+ li.remove();
+ }
+ }
+ }
+ if (fileName != null) {
+ scape = openSavedRun(fileName, (String[]) argsList.toArray(new String[0]));
+ } else {
+ // moved to top of method, so the license agreement has a frame
+ // environment = new UIEnvironment();
+ // OK to do this here, since we know the user has to be in a GUI
+ // environment (don't have to wait to assign params...
+ // environment = new UIEnvironment();
+ // UIEnvironment.checkForLicenseAgreement();
+ scape = openChoose(args);
+ if (scape != null) {
+ scape.getRunner().createEnvironment();
+ } else {
+ System.exit(0);
+ }
+ }
+ }
+ }
+
+ /**
+ * The basic execution cycle of a running scape. In normal usage this methos
+ * is not called directly; use start() instead. You might choose to call this
+ * method directly if you want the calling code to block, for instance, in
+ * order to test that some behavior occurs. Also use this version with
+ * argument "true" if you want to continue using the same thread for restarts.
+ *
+ * @param singlethread
+ * CURRENTLY IGNORED! should the run if restarted continue to use the
+ * same thread?
+ */
+ public void run(boolean singlethread) {
+ if (scape.getUIEnvironment() != null && scape.getUIEnvironment().getRuntimeMode() == AbstractUIEnvironment.RELEASE_RUNTIME_MODE) {
+ try {
+ runMainLoop();
+ } catch (RuntimeException e) {
+ scape.getUIEnvironment().showErrorDialog(scape, e);
+ }
+ } else {
+ runMainLoop();
+ }
+ }
+
+ /**
+ * Requests the scape to start. Note that the scape may not start immeadiatly.
+ *
+ * @see #setRunning
+ */
+ public void start() {
+ if (!isRunning()) {
+ modelThread = new Thread(this, "Ascape Main Execution Loop");
+ modelThread.start();
+ } else {
+ System.out.println("Warning: Tried to start an already running scape.");
+ }
+ }
+
+ public void notify(final ScapeEvent event, final ScapeListener listener) {
+ listener.scapeNotification(event);
+ }
+
+ public void write(final java.io.ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ }
+
+ /**
+ * Requests the scape to stop. Note that the scape will not actually stop
+ * until the current iteration is complete.
+ *
+ * @see #setRunning
+ */
+ public void stop() {
+ setInternalRunning(false);
+ }
+
+ /**
+ * Requests the scape to pause. (Convenience method).
+ *
+ * @see #setPaused
+ */
+ public void pause() {
+ setPaused(true);
+ }
+
+ /**
+ * Requests the scape to resume. (Convenience method).
+ *
+ * @see #setPaused
+ */
+ public void resume() {
+ setPaused(false);
+ }
+
+ /**
+ * Requests the scape to restart.
+ */
+ public void requestRestart() {
+ restartRequested = true;
+ }
+
+ /**
+ * Stops the scape and requests the scape to restart. (Convenience method).
+ *
+ * @see #setRunning
+ */
+ public void restart() {
+ if (running) {
+ stop();
+ restartRequested = true;
+ } else {
+ start();
+ }
+ }
+
+ /**
+ * Method neccessary because of amibiguous null values in simpler signature
+ * methods.
+ */
+ public void openImplementation(String[] args, boolean block) {
+ try {
+ if (args != null) {
+ // first pass of parseSettingArgs,
+ // don't report any parameters not found
+ scape.assignParameters(args, false);
+ }
+ scape.executeOnRoot(Scape.CREATE_RULE);
+ if (args != null) {
+ // second pass of parseSettingArgs,
+ // this time report any parameters not found
+ scape.assignParameters(args, true);
+ }
+ if (scape.getEnvironment() != null) {
+ scape.addView(scape.getEnvironment());
+ }
+
+ scape.executeOnRoot(Scape.CREATE_VIEW_RULE);
+ scape.createViews(args);
+
+ if (Runner.isStartOnOpen()) {
+ if (!block) {
+ start();
+ } else {
+ run();
+ }
+ }
+ } catch (RuntimeException e) {
+ if (getEnvironment() instanceof AbstractUIEnvironment) {
+ ((AbstractUIEnvironment) getEnvironment()).showErrorDialog(scape, e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Creates and runs (if start on open is true) this model scape.
+ *
+ * @param applet
+ * the applet if are we in an applet vm context
+ * @param args
+ * paramter arguments for the scape
+ * @param block
+ * should this call block or run in a new thread?
+ */
+ public void open(Object applet, String[] args, boolean block) {
+ openImplementation(args, block);
+ }
+
+ /**
+ * Creates and runs (if start on open is true) this model scape.
+ *
+ * @param applet
+ * the applet if are we in an applet vm context
+ * @param args
+ * paramter arguments for the scape
+ */
+ public void open(Object applet, String[] args) {
+ openImplementation(args, false);
+ }
+
+ /**
+ * Creates and runs (if start on open is true) this model scape.
+ *
+ * @param args
+ * paramter arguments for the scape
+ * @param block
+ * should this call block or run in a new thread?
+ */
+ public void open(String[] args, boolean block) {
+ openImplementation(args, block);
+ }
+
+ /**
+ * Creates and runs (if start on open is true) this model scape.
+ *
+ * @param args
+ * paramter arguments for the scape
+ */
+ public void open(String[] args) {
+ openImplementation(args, false);
+ }
+
+ /**
+ * Creates and runs (if start on open is true) this model scape.
+ */
+ public void open() {
+ openImplementation(null, false);
+ }
+
+ /**
+ * Creates and runs (if start on open is true) this model scape.
+ *
+ * @param block
+ * should this call block or run in a new thread?
+ */
+ public void open(boolean block) {
+ openImplementation(null, block);
+ }
+
+ /**
+ * Requests the scape to open a saved run.
+ */
+ public void openSavedChoose() {
+ closeAndOpenSavedFinally(null);
+ }
+
+ public abstract void closeAndOpenSavedFinally(Scape oldScape);
+
+ public Object instanceFromName(String modelName) {
+ Object newObject;
+ try {
+ newObject = Thread.currentThread().getContextClassLoader().loadClass(modelName).newInstance();
+ } catch (NullPointerException e) {
+ throw new RuntimeException("An error ocurred while attempting to read " + modelName + ": " + e.getMessage(), e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException("An error ocurred while attempting to read " + modelName + ": " + e.getMessage(), e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("An error ocurred while attempting to read " + modelName + ": " + e.getMessage(), e);
+ } catch (ClassNotFoundException e) {
+ try {
+ Class c = Class.forName(modelName);
+ newObject = c.newInstance();
+ } catch (Exception e2) {
+ throw new RuntimeException("Couldn't find class: " + modelName);
+ }
+ }
+ return newObject;
+ }
+
+ /**
+ * Constructs, creates and runs (if start on open is true) the supplied model.
+ *
+ * @deprecated Applets are no longer executed this way
+ * @param modelName
+ * the fully qualified name of the Java class for the model's root
+ * scape
+ * @param applet
+ * the applet if are we in an applet vm context
+ * @param args
+ * paramter arguments for the scape
+ * @param block
+ * should this call block or run in a new thread?
+ */
+ public Scape open(String modelName, Object applet, String[] args, boolean block) {
+ return open(modelName, args, block);
+ }
+
+ /**
+ * Constructs, creates and runs the supplied model.
+ *
+ * @param modelName
+ * the fully qualified name of the Java class for the model's root
+ * scape
+ * @param args
+ * paramter arguments for the scape
+ */
+ public Scape open(String modelName, String[] args) {
+ return open(modelName, args, false);
+ }
+
+ /**
+ * Constructs, creates and runs the supplied model.
+ *
+ * @param modelName
+ * the fully qualified name of the Java class for the model's root
+ * scape
+ * @param args
+ * paramter arguments for the scape
+ * @param block
+ * should this call block or run in a new thread?
+ */
+ public Scape open(String modelName, String[] args, boolean block) {
+
+ Scape newAgent = (Scape) instanceFromName(modelName);
+ setRootScape(newAgent);
+ open(args, block);
+ return getRootScape();
+ }
+
+ /**
+ * Constructs, creates and runs the supplied model.
+ *
+ * @deprecated Applets are no longer executed this way
+ * @param modelName
+ * the fully qualified name of the Java class for the model's root
+ * scape
+ * @param applet
+ * the applet if are we in an applet vm context
+ */
+ public Scape open(String modelName, Object applet) {
+ return open(modelName, null, null, false);
+ }
+
+ /**
+ * Constructs, creates and runs the supplied model.
+ *
+ * @param modelName
+ * the fully qualified name of the Java class for the model's root
+ * scape
+ */
+ public Scape open(String modelName, boolean block) {
+ return open(modelName, null, null, block);
+ }
+
+ /**
+ * Constructs, creates and runs the supplied model.
+ *
+ * @param modelName
+ * the fully qualified name of the Java class for the model's root
+ * scape
+ */
+ public Scape openInstance(String modelName) {
+ return open(modelName, null, new String[0], false);
+ }
+
+ /**
+ * Requests the scape to open a model, providing UI for this purpose.
+ */
+ public Scape openChoose() {
+ return openChoose(null);
+ }
+
+ /**
+ * Requests the scape to open a model, providing UI for this purpose.
+ */
+ public Scape openChoose(String[] args) {
+ String modelName = ((AbstractUIEnvironment) environment).openDialog();
+ Scape scape = null;
+ if (modelName != null) {
+ scape = open(modelName, args);
+ }
+ return scape;
+ }
+
+ /*
+ * To be done (perhaps) Opens the specified scape from a class file.
+ */
+ /*
+ * public static void open(File file) { FileInputStream f = new
+ * FileInputStream(file); ObjectInputStream s = new ObjectInputStream(f); try
+ * { Scape newScape = (Scape) s.readObject(); } catch (ClassNotFoundException
+ * e) { JOptionPane.showMessageDialog(null, "A class couldn't be found (make
+ * sure you have all the appropriate model classes installed): " + e, "Error",
+ * JOptionPane.INFORMATION_MESSAGE); } }
+ */
+
+ /**
+ * Save the state of the scape to a file.
+ */
+ public abstract void saveChoose();
+
+ public void close() {
+ closeRequested = true;
+ if (running) {
+ // Running, so we have to allow current iteration to finish
+ stop();
+ } else {
+ closeFinally();
+ }
+ }
+
+ /**
+ * Closes the application; allowing views to close themseleves gracefully. Do
+ * not call this method directly unless you want to force close; call
+ * <code>close()</code> instead, allowing a running scape to stop gracefully.
+ * Override this method if you want to provide any scape related pre-quit
+ * finalization or clean-up.
+ *
+ * @see #quit
+ */
+ public void closeFinally() {
+ dataGroup = null;
+ // Send an event to self for quit
+ scape.executeOnRoot(new NotifyViews(ScapeEvent.REQUEST_CLOSE));
+ waitForViewsUpdate();
+ }
+
+ /**
+ * Exits the application; calling stop if running and allowing views to close
+ * themseleves gracefully. Override <code>quitFinally</code> if you want to
+ * provide any pre-quit finalization or clean-up.
+ *
+ * @see #quitFinally
+ */
+ public void quit() {
+ if (inMainLoop) {
+ quitRequested = true;
+ // Running, so we have to allow current iteration to finish
+ stop();
+ }
+ // Only one chance a quit request, otherwise we assume that the scape is
+ // allready fulfilling it.
+ else if (!quitRequested) {
+ quitFinally();
+ }
+ }
+
+ /**
+ * Exits the application; allowing views to close themseleves gracefully. Do
+ * not call this method directly unless you want to force quit; call
+ * <code>quit()</code> instead, allowing a running scape to stop gracefully.
+ * Override this method if you want to provide any scape related pre-quit
+ * finalization or clean-up.
+ *
+ * @see #quit
+ */
+ public void quitFinally() {
+ closeFinally();
+ scape.executeOnRoot(new NotifyViews(ScapeEvent.REQUEST_QUIT));
+ waitForViewsUpdate();
+ exit();
+ }
+
+ /**
+ * Final kill. Calls System exit, which appears neccessary for vm even when
+ * code has finished.
+ */
+ public static void exit() {
+ try {
+ System.exit(0);
+ } catch (SecurityException e) {
+ System.out.println("Can't quit in this security context. (Scape is probably running in browser or viewer; quit or change that.)");
+ }
+ }
+
+ public void createEnvironment() {
+ if (environment == null) {
+ environment = new RuntimeEnvironment();
+ }
+ }
+
+ public static boolean isDisplayGraphics() {
+ try {
+ return displayGraphics && !GraphicsEnvironment.isHeadless();
+ } catch (HeadlessException e) {
+ return false;
+ }
+ }
+
+ public static void setDisplayGraphics(boolean displayGraphics) {
+ Runner.displayGraphics = displayGraphics;
+ }
+
+ public static boolean isServeGraphics() {
+ return serveGraphics;
+ }
+
+ public static void setServeGraphics(boolean serveGraphics) {
+ Runner.serveGraphics = serveGraphics;
+ }
+
+ public static boolean isMultiWinEnvironment() {
+ return muiltWinEnvironment;
+ }
+
+ public static void setMultiWinEnvironment(boolean muiltWinEnvironment) {
+ Runner.muiltWinEnvironment = muiltWinEnvironment;
+ }
+
+ /**
+ * Sets the period name for the delegate
+ *
+ * @return the periodName
+ */
+ public String getPeriodName() {
+ return periodName;
+ }
+
+ /**
+ * Sets periodName for the ModelRoot object.
+ *
+ * @param periodName
+ * the periodName
+ */
+ public void setPeriodName(String periodName) {
+ this.periodName = periodName;
+ }
+
+ /**
+ * Gets the description for the ModelRoot object.
+ *
+ * @return the description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets description for the ModelRoot object.
+ *
+ * @param description
+ * the description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Returns a brief descripiton (including credits) of the scape or of the
+ * model, if this is root scape. Plaintext.
+ *
+ * @return the description
+ */
+ public String getHTMLDescription() {
+ return HTMLDescription;
+ }
+
+ /**
+ * Sets an html-formatted description to be used for the model as a whole.
+ *
+ * @param HTMLdescription
+ * the description
+ */
+ public void setHTMLDescription(String HTMLdescription) {
+ this.HTMLDescription = HTMLdescription;
+ }
+
+ /**
+ * Returns the period that this model started.
+ *
+ * @return the startPeriod
+ */
+ public int getStartPeriod() {
+ return startPeriod;
+ }
+
+ /**
+ * Gets the startOnOpen for the Runner object. Start on Open is static because
+ * we may not have a scape context.
+ *
+ * @return the startOnOpen
+ */
+ public static boolean isStartOnOpen() {
+ return startOnOpen;
+ }
+
+ /**
+ * Sets startOnOpen for the ModelRoot object.
+ *
+ * @param startOnOpen
+ * the startOnOpen
+ */
+ public static void setStartOnOpen(boolean _startOnOpen) {
+ startOnOpen = _startOnOpen;
+ }
+
+ /**
+ * Sets the start period for this scape. The start period is the period this
+ * scape is given when a model run is started.
+ *
+ * @param startPeriod
+ * the period to begin runs at
+ * @throws org.ascape.model.space.SpatialTemporalException
+ * exception
+ */
+ public void setStartPeriod(int startPeriod) throws SpatialTemporalException {
+ if (startPeriod >= earliestPeriod) {
+ this.startPeriod = startPeriod;
+ } else {
+ throw new SpatialTemporalException("Tried to set start period before earliest period");
+ }
+ }
+
+ /**
+ * Returns the period this scape stops running at. By default, the lesser of
+ * latest period and integer maximum value (effectively unlimited.)
+ *
+ * @return the stopPeriod
+ */
+ public int getStopPeriod() {
+ return stopPeriod;
+ }
+
+ /**
+ * Sets the stop period for this scape. The stop period is the period that the
+ * scape is automatically stopped at. The scape may be automatically set to
+ * start agina at start value is the scape is set to restart.
+ *
+ * @param stopPeriod
+ * the period the scape will stop at upon reaching
+ * @see #setAutoRestart
+ * @throws org.ascape.model.space.SpatialTemporalException
+ * exception
+ */
+ public void setStopPeriod(int stopPeriod) throws SpatialTemporalException {
+ if (stopPeriod <= latestPeriod) {
+ this.stopPeriod = stopPeriod;
+ } else {
+ throw new SpatialTemporalException("Tried to set stop period after latest period");
+ }
+ }
+
+ /**
+ * Gets the pausePeriod for the ModelRoot object.
+ *
+ * @return the pausePeriod
+ */
+ public int getPausePeriod() {
+ return pausePeriod;
+ }
+
+ /**
+ * Sets pausePeriod for the ModelRoot object.
+ *
+ * @param pausePeriod
+ * the pausePeriod
+ */
+ public void setPausePeriod(int pausePeriod) {
+ this.pausePeriod = pausePeriod;
+ }
+
+ /**
+ * Gets the earliestPeriod for the ModelRoot object.
+ *
+ * @return the earliestPeriod
+ */
+ public int getEarliestPeriod() {
+ return earliestPeriod;
+ }
+
+ /**
+ * Sets the earliest period this scape is expected to be run at. 0 by default.
+ *
+ * @param earliestPeriod
+ * the lowest period value this scape can have
+ */
+ public void setEarliestPeriod(int earliestPeriod) {
+ this.earliestPeriod = earliestPeriod;
+ if (startPeriod < earliestPeriod) {
+ try {
+ setStartPeriod(earliestPeriod);
+ }
+ // "Can't" happen
+ catch (SpatialTemporalException e) {
+ throw new RuntimeException("Internal Logic Error");
+ }
+ }
+ }
+
+ /**
+ * Gets the latestPeriod for the ModelRoot object.
+ *
+ * @return the latestPeriod
+ */
+ public int getLatestPeriod() {
+ return latestPeriod;
+ }
+
+ /**
+ * Sets the latest period this scape is expected to be run at. Max of integer
+ * (effectively unlimited) by default.
+ *
+ * @param latestPeriod
+ * the highest period value this scape can have
+ */
+ public void setLatestPeriod(int latestPeriod) {
+ this.latestPeriod = latestPeriod;
+ if (stopPeriod > latestPeriod) {
+ try {
+ setStopPeriod(latestPeriod);
+ }
+ // "Can't" happen
+ catch (SpatialTemporalException e) {
+ throw new RuntimeException("Internal Logic Error");
+ }
+ }
+ }
+
+ /**
+ * Gets the restartingViews for the ModelRoot object.
+ *
+ * @return the restartingViews
+ */
+ public List getRestartingViews() {
+ return restartingViews;
+ }
+
+ /**
+ * Sets restartingViews for the ModelRoot object.
+ *
+ * @param restartingViews
+ * the restartingViews
+ */
+ public void setRestartingViews(List restartingViews) {
+ this.restartingViews = restartingViews;
+ }
+
+ /**
+ * Gets the AutoRestart for the ModelRoot object.
+ *
+ * @return the Restart state
+ */
+ public boolean isAutoRestart() {
+ return autoRestart;
+ }
+
+ /**
+ * Sets Restart for the ModelRoot object.
+ *
+ * @param autoRestart
+ * should the model restart when it ends?
+ */
+ public void setAutoRestart(boolean autoRestart) {
+ this.autoRestart = autoRestart;
+ }
+
+ /**
+ * Is the supplied period a valid period for this scape?
+ *
+ * @param period
+ * the period to test
+ * @return true if within earliest and latest periods, false otherwise
+ */
+ public boolean isValidPeriod(int period) {
+ return period >= earliestPeriod && period <= latestPeriod;
+ }
+
+ /**
+ * Returns the path in which all files should by default be stored to and
+ * retrieved from. Nonstatic, so that parameter can automatically be set from
+ * command line, but backing variable is static. Default is "./", can be
+ * modified by calling setHome or providing an ascape.home java property.
+ * (This may change now since it is no longer neccesary.)
+ *
+ * @return the home
+ */
+ public String getHome() {
+ if (home == null) {
+ home = "./";
+ try {
+ home = System.getProperty("ascape.home", home);
+ }
+ // Ignore security exception; we may be running in an environment
+ // such as an applet where we can't get ascape home
+ // no probel,m we just need to make sure that lib, etc. are in the
+ // right place.
+ catch (SecurityException e) {
+ }
+ }
+ return home;
+ }
+
+ /**
+ * Sets the path in which to store all scape related files. Nonstatic, so that
+ * parameter can automatically be set from command line, but backing variable
+ * is static.
+ *
+ * @param home
+ * the home
+ */
+ public void setHome(String home) {
+ this.home = home;
+ }
+
+ public RuntimeEnvironment getEnvironment() {
+ return environment;
+ }
+
+ public boolean isBeginningDeserializedRun() {
+ return beginningDeserializedRun;
+ }
+
+ public void setBeginningDeserializedRun(boolean beginningDeserializedRun) {
+ this.beginningDeserializedRun = beginningDeserializedRun;
+ }
+
+ public boolean isCloseAndOpenNewRequested() {
+ return closeAndOpenNewRequested;
+ }
+
+ public void setCloseAndOpenNewRequested(boolean closeAndOpenNewRequested) {
+ this.closeAndOpenNewRequested = closeAndOpenNewRequested;
+ }
+
+ public boolean isCloseAndOpenSavedRequested() {
+ return closeAndOpenSavedRequested;
+ }
+
+ public void setCloseAndOpenSavedRequested(boolean closeAndOpenSavedRequested) {
+ this.closeAndOpenSavedRequested = closeAndOpenSavedRequested;
+ }
+
+ public boolean isCloseRequested() {
+ return closeRequested;
+ }
+
+ public void setCloseRequested(boolean closeRequested) {
+ this.closeRequested = closeRequested;
+ }
+
+ public boolean isInMainLoop() {
+ return inMainLoop;
+ }
+
+ public void setInMainLoop(boolean inMainLoop) {
+ this.inMainLoop = inMainLoop;
+ }
+
+ public int getIteration() {
+ return iteration;
+ }
+
+ public void setIteration(int iteration) {
+ this.iteration = iteration;
+ }
+
+ public boolean isOpenRequested() {
+ return openRequested;
+ }
+
+ public void setOpenRequested(boolean openRequested) {
+ this.openRequested = openRequested;
+ }
+
+ public boolean isPaused() {
+ return paused;
+ }
+
+ public void setPaused(boolean paused) {
+ this.paused = paused;
+ }
+
+ public int getPeriod() {
+ return period;
+ }
+
+ public void setPeriod(int period) {
+ this.period = period;
+ }
+
+ public boolean isQuitRequested() {
+ return quitRequested;
+ }
+
+ public void setQuitRequested(boolean quitRequested) {
+ this.quitRequested = quitRequested;
+ }
+
+ public boolean isRestartRequested() {
+ return restartRequested;
+ }
+
+ public void setRestartRequested(boolean restartRequested) {
+ this.restartRequested = restartRequested;
+ }
+
+ public boolean isRunning() {
+ return running;
+ }
+
+ public void setRunning(boolean running) {
+ if (running) {
+ start();
+ } else {
+ stop();
+ }
+ }
+
+ public void setInternalRunning(boolean running) {
+ this.running = running;
+ }
+
+ public boolean isSaveRequested() {
+ return saveRequested;
+ }
+
+ public void setSaveRequested(boolean saveRequested) {
+ this.saveRequested = saveRequested;
+ }
+
+ public boolean isStep() {
+ return step;
+ }
+
+ public void setStep(boolean step) {
+ this.step = step;
+ }
+
+ public DataGroup getData() {
+ return dataGroup;
+ }
+
+ public void setRootScape(Scape scape) {
+ this.scape = scape;
+ scape.setRunner(this);
+ dataGroup = new DataGroup();
+ dataGroup.setScape(scape);
+ }
+
+ public Scape getRootScape() {
+ return scape;
+ }
+
+ public void setEnvironment(RuntimeEnvironment environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * @return <code>true</code> if the {@link #modelThread} is still running and
+ * alive
+ */
+ protected boolean isModelThreadAlive() {
+ return modelThread != null && modelThread.isAlive();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/AbstractLifecycleListener.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/AbstractLifecycleListener.java
index 667072c7..06c2ad31 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/AbstractLifecycleListener.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/AbstractLifecycleListener.java
@@ -15,10 +15,10 @@
*/
package org.eclipse.amp.axf.core;
-// TODO: Auto-generated Javadoc
/**
- * The listener interface for receiving abstractModel events. The class that is interested in processing a abstractModel
- * event implements this interface, and the object created with that class is registered with a component using the
+ * The listener interface for receiving abstractModel events. The class that is
+ * interested in processing a abstractModel event implements this interface, and
+ * the object created with that class is registered with a component using the
* component's <code>addAbstractModelListener<code> method. When
* the abstractModel event occurs, that object's appropriate
* method is invoked.
@@ -27,122 +27,122 @@ package org.eclipse.amp.axf.core;
*/
public class AbstractLifecycleListener implements ILifeCycleListener {
- private String name;
-
- private IStateListener listener;
-
- /**
- * Instantiates a new abstract model listener.
- */
- public AbstractLifecycleListener() {
- listener = new LifecycleObservationAdapter(this);
- }
-
- /**
- * Instantiates a new abstract model listener.
- *
- * @param name the name
- */
- public AbstractLifecycleListener(String name) {
- this();
- this.name = name;
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observationEnd(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observationEnd(IObservationProvider observed) {
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observationEnding(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observationEnding(IObservationProvider observed) {
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeCreate(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observeCreate(IObservationProvider observed) {
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeInitialize(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observeInitialize(IObservationProvider observed) {
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeStart(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observeStart(IObservationProvider observed) {
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeStop(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observeStop(IObservationProvider observed) {
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeUpdate(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observeUpdate(IObservationProvider observed) {
- }
-
- /**
- * @param observed
- * @see org.eclipse.amp.axf.core.ILifeCycleListener#observing(org.eclipse.amp.axf.core.IObservationProvider)
- */
- public void observing(IObservationProvider observed) {
- }
-
- /**
- * @param key
- * @param updated
- * @see org.eclipse.amp.axf.core.IStateListener#stateChange(java.lang.Object, java.lang.Object)
- */
- public void stateChange(Object key, Object updated) {
- listener.stateChange(key, updated);
- }
-
- /**
- * @return the listener
- */
- public IStateListener getListener() {
- return listener;
- }
-
- /**
- * Gets the name.
- *
- * @return the name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the name.
- *
- * @param name the new name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * @return
- * @see java.lang.Object#toString()
- */
- public String toString() {
- return name;
- }
+ private String name;
+
+ private IStateListener listener;
+
+ /**
+ * Instantiates a new abstract model listener.
+ */
+ public AbstractLifecycleListener() {
+ listener = new LifecycleObservationAdapter(this);
+ }
+
+ /**
+ * Instantiates a new abstract model listener.
+ *
+ * @param name
+ * the name
+ */
+ public AbstractLifecycleListener(String name) {
+ this();
+ this.name = name;
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observationEnd(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observationEnd(IObservationProvider observed) {
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observationEnding(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observationEnding(IObservationProvider observed) {
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeCreate(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observeCreate(IObservationProvider observed) {
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeInitialize(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observeInitialize(IObservationProvider observed) {
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeStart(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observeStart(IObservationProvider observed) {
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeStop(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observeStop(IObservationProvider observed) {
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observeUpdate(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observeUpdate(IObservationProvider observed) {
+ }
+
+ /**
+ * @param observed
+ * @see org.eclipse.amp.axf.core.ILifeCycleListener#observing(org.eclipse.amp.axf.core.IObservationProvider)
+ */
+ public void observing(IObservationProvider observed) {
+ }
+
+ /**
+ * @param key
+ * @param updated
+ * @see org.eclipse.amp.axf.core.IStateListener#stateChange(java.lang.Object,
+ * java.lang.Object)
+ */
+ public void stateChange(Object key, Object updated) {
+ listener.stateChange(key, updated);
+ }
+
+ /**
+ * @return the listener
+ */
+ public IStateListener getListener() {
+ return listener;
+ }
+
+ /**
+ * Gets the name.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name.
+ *
+ * @param name
+ * the new name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IEngine.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IEngine.java
index 6747c170..95bbd132 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IEngine.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IEngine.java
@@ -17,88 +17,91 @@ package org.eclipse.amp.axf.core;
import org.eclipse.amp.axf.time.ITimeGranularity;
-// TODO: Auto-generated Javadoc
/**
* The Interface IEngine.
*/
public interface IEngine {
- /**
- * Close.
- */
- void close();
+ /**
+ * Close.
+ */
+ void close();
- /**
- * Close finally.
- */
- void closeFinally();
+ /**
+ * Close finally.
+ */
+ void closeFinally();
- /**
- * Checks if is close requested.
- *
- * @return true, if is close requested
- */
- boolean isCloseRequested();
+ /**
+ * Checks if is close requested.
+ *
+ * @return true, if is close requested
+ */
+ boolean isCloseRequested();
- /**
- * Gets the model thread.
- *
- * @return the model thread
- */
- Thread getModelThread();
+ /**
+ * @return <code>true</code> if the {@link Thread} that runs the engine is
+ * still alive
+ */
+ boolean isThreadAlive();
- /**
- * Checks if is running.
- *
- * @return true, if is running
- */
- boolean isRunning();
+ /**
+ * Checks if is running.
+ *
+ * @return true, if is running
+ */
+ boolean isRunning();
- /**
- * Checks if is paused.
- *
- * @return true, if is paused
- */
- boolean isPaused();
+ /**
+ * Checks if is paused.
+ *
+ * @return true, if is paused
+ */
+ boolean isPaused();
- /**
- * Stop.
- */
- void stop();
+ /**
+ * Stop.
+ */
+ void stop();
- /**
- * Control.
- *
- * @param ModelControl the model control
- */
- void control(EngineControl ModelControl);
+ /**
+ * Control.
+ *
+ * @param ModelControl
+ * the model control
+ */
+ void control(EngineControl ModelControl);
- /**
- * Observation complete.
- *
- * @param observer the observer
- */
- void observationComplete(ILifeCycleListener observer);
+ /**
+ * Observation complete.
+ *
+ * @param observer
+ * the observer
+ */
+ void observationComplete(ILifeCycleListener observer);
- /**
- * Gets the model.
- *
- * @return the model
- */
- IObservationProvider getModel();
+ /**
+ * Gets the model.
+ *
+ * @return the model
+ */
+ IObservationProvider getModel();
- /**
- * Sets the update granularity. This defines how often observers expect to receive state change notifications.
- * Regardless of this value, engines should always provide life-cycle notifications.
- *
- * @param granularity the desired update granularity (engine specific).
- */
- void setUpdateGranularity(ITimeGranularity granularity);
+ /**
+ * Sets the update granularity. This defines how often observers expect to
+ * receive state change notifications. Regardless of this value, engines
+ * should always provide life-cycle notifications.
+ *
+ * @param granularity
+ * the desired update granularity (engine specific).
+ */
+ void setUpdateGranularity(ITimeGranularity granularity);
- /**
- * Returns the update granularity.
- *
- * @param granularity the desired update granularity (engine specific).
- */
- ITimeGranularity getUpdateGranularity();
+ /**
+ * Returns the update granularity.
+ *
+ * @param granularity
+ * the desired update granularity (engine specific).
+ */
+ ITimeGranularity getUpdateGranularity();
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IObservationProvider.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IObservationProvider.java
index 074b0cae..ff0fadff 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IObservationProvider.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/IObservationProvider.java
@@ -16,9 +16,10 @@
package org.eclipse.amp.axf.core;
/**
- * A model object capable of providing complete independent life-cycle information and change reporting. During the
- * course of its existence as an instantiation within a computational context (i.e. a given vm or distributed system), a
- * model may only transition through the following changes in state:
+ * A model object capable of providing complete independent life-cycle
+ * information and change reporting. During the course of its existence as an
+ * instantiation within a computational context (i.e. a given vm or distributed
+ * system), a model may only transition through the following changes in state:
*
* <pre>
* [Object creation] -> Created
@@ -34,17 +35,20 @@ package org.eclipse.amp.axf.core;
* Ending -> Ended
* </pre>
*
- * Of course, a model may treat any transition as trivially as desired and so may effectively transition through
- * multiple state changes at once (though any models also implementing ILifecycle notifier must report each of these
- * transitions individually). A given model then should not undergo the following transition at any point:
+ * Of course, a model may treat any transition as trivially as desired and so
+ * may effectively transition through multiple state changes at once (though any
+ * models also implementing ILifecycle notifier must report each of these
+ * transitions individually). A given model then should not undergo the
+ * following transition at any point:
*
* <pre>
* Ended -> {Any other state}
* </pre>
*
- * A model can be in multiple states at once; in fact, given the transition rules above, if a model is in one of the
- * following states then they must also be in one of the first set of states and cannot be in any of the following set
- * of states.
+ * A model can be in multiple states at once; in fact, given the transition
+ * rules above, if a model is in one of the following states then they must also
+ * be in one of the first set of states and cannot be in any of the following
+ * set of states.
*
* <pre>
* Initialized: {Created} {Stopped, Ended, Ending}
@@ -59,88 +63,101 @@ package org.eclipse.amp.axf.core;
*/
public interface IObservationProvider {
- /**
- * Has the model been created? Should return true if observable start time components have been created. It is up to
- * implementation to define semantics of when a model is created vs. when it is initialized, but the following
- * guidelines are recommended to ensure good model repeatability and performance. To be considered created, a model
- * needs:
- *
- * <pre>
- * 1. Internally consistent state.
- * 2. Consistent start state across invocations with same input sets.
- * 3. Consistent (and ideally, useful and complete!) external state through all supplied providers.
- * 4. Accurately updated life cycle state.
- * 5. In general, all basic component structure constructed.
- * </pre>
- *
- * A good way to think of this state is as having all scaffolding in place. As outlined in #isInitialized, there
- * should be no calls to random functions before the model has passed through this state.
- *
- * It is up to the implementation to decide (and seems generally reasonable) whether to allow a model to be
- * re-created, and clients should generally handle this situation gracefully.
- *
- * @see isInitialized for important issue re: randomness and repeatability
- *
- * @return true, if the model is created
- */
- public abstract boolean isCreated();
+ /**
+ * Has the model been created? Should return true if observable start time
+ * components have been created. It is up to implementation to define
+ * semantics of when a model is created vs. when it is initialized, but the
+ * following guidelines are recommended to ensure good model repeatability and
+ * performance. To be considered created, a model needs:
+ *
+ * <pre>
+ * 1. Internally consistent state.
+ * 2. Consistent start state across invocations with same input sets.
+ * 3. Consistent (and ideally, useful and complete!) external state through all supplied providers.
+ * 4. Accurately updated life cycle state.
+ * 5. In general, all basic component structure constructed.
+ * </pre>
+ *
+ * A good way to think of this state is as having all scaffolding in place. As
+ * outlined in #isInitialized, there should be no calls to random functions
+ * before the model has passed through this state.
+ *
+ * It is up to the implementation to decide (and seems generally reasonable)
+ * whether to allow a model to be re-created, and clients should generally
+ * handle this situation gracefully.
+ *
+ * @see isInitialized for important issue re: randomness and repeatability
+ *
+ * @return true, if the model is created
+ */
+ public abstract boolean isCreated();
- /**
- * Has the model been initialized? Should return true if all time 0 components have been created and initialized. It
- * is up to implementation to define semantics of when a model is created vs. when it is initialized, but the
- * following guidelines are recommended to ensure good model repeatability and performance. To be considered
- * initialized, a model ideally has:
- *
- * <pre>
- * 1. All model components necessary for running the model forward have been created and had initial state set.
- * 2. Model state should be recoverable to initialized state after stopping and (re) starting without passing through created state.
- * 3. For a given set of inputs, under (2) this state should be be consistent, regardless of whether the model has been newly created or repeatedly returned to initialized state.
- * </pre>
- *
- * Note a very important consequence of the above guidelines for initialized state. No random decisions affecting
- * model state should occur before the model leaves the start state and enters the initializing state as those
- * decisions would make it impossible to consistently re-enter the same state.
- *
- * @return true, if the model is fully initialized
- */
- public abstract boolean isInitialized();
+ /**
+ * Has the model been initialized? Should return true if all time 0 components
+ * have been created and initialized. It is up to implementation to define
+ * semantics of when a model is created vs. when it is initialized, but the
+ * following guidelines are recommended to ensure good model repeatability and
+ * performance. To be considered initialized, a model ideally has:
+ *
+ * <pre>
+ * 1. All model components necessary for running the model forward have been created and had initial state set.
+ * 2. Model state should be recoverable to initialized state after stopping and (re) starting without passing through created state.
+ * 3. For a given set of inputs, under (2) this state should be be consistent, regardless of whether the model has been newly created or repeatedly returned to initialized state.
+ * </pre>
+ *
+ * Note a very important consequence of the above guidelines for initialized
+ * state. No random decisions affecting model state should occur before the
+ * model leaves the start state and enters the initializing state as those
+ * decisions would make it impossible to consistently re-enter the same state.
+ *
+ * @return true, if the model is fully initialized
+ */
+ public abstract boolean isInitialized();
- /**
- * Has the model been stopped? When a model has been stopped, it cannot return to active state without being (re)
- * started.
- *
- * @return the period
- */
- boolean isStopped();
+ /**
+ * Has the model been stopped? When a model has been stopped, it cannot return
+ * to active state without being (re) started.
+ *
+ * @return the period
+ */
+ boolean isStopped();
- /**
- * Has the model been started?
- *
- * @return the period
- */
- boolean isStarted();
+ /**
+ * Has the model been started?
+ *
+ * @return the period
+ */
+ boolean isRunning();
- /**
- * Is the model currently active? Any model that has been started and has not stopped is considered active, even if
- * the model is not actively executing (using CPU cycles or advancing from one state to another.)
- *
- * @return the period
- */
- boolean isActive();
+ /**
+ * @return true if the model has been set to pause
+ */
+ boolean isPaused();
- /**
- * Is the model currently in the process of ending itself? This state gives views a chance to get any final state
- * while the model is still guaranteed to be available and consistent.
- *
- * @return the period
- */
- boolean isEnding();
+ /**
+ * Is the model currently active? Any model that has been started and has not
+ * stopped is considered active, even if the model is not actively executing
+ * (using CPU cycles or advancing from one state to another.)
+ *
+ * @return the period
+ */
+ boolean isActive();
- /**
- * Has model has ended? In general, a model that has ended can never be (re) started. It is up to implementations to
- * define whether model state is consistent and stable following the transition to ended state.
- *
- * @return the period
- */
- boolean isEnded();
+ /**
+ * Is the model currently in the process of ending itself? This state gives
+ * views a chance to get any final state while the model is still guaranteed
+ * to be available and consistent.
+ *
+ * @return the period
+ */
+ boolean isEnding();
+
+ /**
+ * Has model has ended? In general, a model that has ended can never be (re)
+ * started. It is up to implementations to define whether model state is
+ * consistent and stable following the transition to ended state.
+ *
+ * @return the period
+ */
+ boolean isEnded();
} \ No newline at end of file
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifeCycleState.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifeCycleState.java
index 962a4687..538d7611 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifeCycleState.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifeCycleState.java
@@ -12,12 +12,12 @@
*
* </copyright>
*
-*/
+ */
package org.eclipse.amp.axf.core;
/**
* The Enum LifeCycleState.
*/
public enum LifeCycleState {
- OBSERVED, CREATE, INITIALIZE, SETUP, START, UPDATE, STOP, ENDING, END
+ OBSERVED, CREATE, INITIALIZE, SETUP, START, UPDATE, PAUSED, STOP, ENDING, END
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifecycleObservationAdapter.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifecycleObservationAdapter.java
index 05e76eb2..cb7b93aa 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifecycleObservationAdapter.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.core/src/org/eclipse/amp/axf/core/LifecycleObservationAdapter.java
@@ -15,59 +15,60 @@
*/
package org.eclipse.amp.axf.core;
-// TODO: Auto-generated Javadoc
/**
* The Class LifecycleObservationAdapter.
*/
public class LifecycleObservationAdapter implements IStateListener {
- ILifeCycleListener lifeCycleListener;
+ ILifeCycleListener lifeCycleListener;
- /**
- * Instantiates a new lifecycle observation adapter.
- *
- * @param lifeCycleListener the life cycle listener
- */
- public LifecycleObservationAdapter(ILifeCycleListener lifeCycleListener) {
- super();
- this.lifeCycleListener = lifeCycleListener;
- }
+ /**
+ * Instantiates a new lifecycle observation adapter.
+ *
+ * @param lifeCycleListener
+ * the life cycle listener
+ */
+ public LifecycleObservationAdapter(ILifeCycleListener lifeCycleListener) {
+ super();
+ this.lifeCycleListener = lifeCycleListener;
+ }
- /**
- * @param notifyType
- * @param observed
- * @see org.eclipse.amp.axf.core.IStateListener#stateChange(java.lang.Object, java.lang.Object)
- */
- public void stateChange(Object notifyType, Object observed) {
- if (notifyType instanceof LifeCycleState && observed instanceof IObservationProvider) {
- IObservationProvider provider = (IObservationProvider) observed;
- switch ((LifeCycleState) notifyType) {
- case OBSERVED:
- lifeCycleListener.observing(provider);
- return;
- case CREATE:
- lifeCycleListener.observeCreate(provider);
- return;
- case INITIALIZE:
- lifeCycleListener.observeInitialize(provider);
- return;
- case START:
- lifeCycleListener.observeStart(provider);
- return;
- case UPDATE:
- lifeCycleListener.observeUpdate(provider);
- return;
- case STOP:
- lifeCycleListener.observeStop(provider);
- return;
- case END:
- lifeCycleListener.observationEnd(provider);
- return;
- case ENDING:
- lifeCycleListener.observationEnding(provider);
- return;
- }
- }
- }
+ /**
+ * @param notifyType
+ * @param observed
+ * @see org.eclipse.amp.axf.core.IStateListener#stateChange(java.lang.Object,
+ * java.lang.Object)
+ */
+ public void stateChange(Object notifyType, Object observed) {
+ if (notifyType instanceof LifeCycleState && observed instanceof IObservationProvider) {
+ IObservationProvider provider = (IObservationProvider) observed;
+ switch ((LifeCycleState) notifyType) {
+ case OBSERVED:
+ lifeCycleListener.observing(provider);
+ return;
+ case CREATE:
+ lifeCycleListener.observeCreate(provider);
+ return;
+ case INITIALIZE:
+ lifeCycleListener.observeInitialize(provider);
+ return;
+ case START:
+ lifeCycleListener.observeStart(provider);
+ return;
+ case UPDATE:
+ lifeCycleListener.observeUpdate(provider);
+ return;
+ case STOP:
+ lifeCycleListener.observeStop(provider);
+ return;
+ case END:
+ lifeCycleListener.observationEnd(provider);
+ return;
+ case ENDING:
+ lifeCycleListener.observationEnding(provider);
+ return;
+ }
+ }
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/.classpath b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/.classpath
index 304e8618..5168cee8 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/.classpath
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/.classpath
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/META-INF/MANIFEST.MF b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/META-INF/MANIFEST.MF
index 12ed61e4..dfe6cffa 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/META-INF/MANIFEST.MF
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/META-INF/MANIFEST.MF
@@ -10,7 +10,8 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.ui,
org.eclipse.core.expressions,
org.eclipse.amp.axf.core,
- org.eclipse.amp.axf.views
+ org.eclipse.amp.axf.views,
+ org.junit;bundle-version="4.8.1"
Export-Package: org.eclipse.amp.axf.ide,
org.eclipse.amp.axf.ide.handlers,
org.eclipse.amp.axf.ide.view
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/plugin.xml b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/plugin.xml
index 66ee7370..8ca92400 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/plugin.xml
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/plugin.xml
@@ -458,5 +458,107 @@
class="org.eclipse.amp.axf.ide.AXFWorkbenchPlugin">
</startup>
</extension>
+ <extension
+ point="org.eclipse.ui.handlers">
+ <handler
+ class="org.eclipse.amp.axf.ide.handlers.StartHandler"
+ commandId="org.eclipse.amp.axf.ui.start">
+ <enabledWhen>
+ <with
+ variable="org.eclipse.amp.axf.ide.engine.state">
+ <equals
+ value="IDLE">
+ </equals>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.amp.axf.ide.handlers.StopHandler"
+ commandId="org.eclipse.amp.axf.ui.stop">
+ <enabledWhen>
+ <with
+ variable="org.eclipse.amp.axf.ide.engine.state">
+ <equals
+ value="RUNNING">
+ </equals>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.amp.axf.ide.handlers.PauseHandler"
+ commandId="org.eclipse.amp.axf.ui.pause">
+ <enabledWhen>
+ <with
+ variable="org.eclipse.amp.axf.ide.engine.state">
+ <equals
+ value="RUNNING">
+ </equals>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.amp.axf.ide.handlers.ResumeHandler"
+ commandId="org.eclipse.amp.axf.ui.resume">
+ <enabledWhen>
+ <with
+ variable="org.eclipse.amp.axf.ide.engine.state">
+ <equals
+ value="PAUSED">
+ </equals>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.amp.axf.ide.handlers.RestartHandler"
+ commandId="org.eclipse.amp.axf.ui.restart">
+ <enabledWhen>
+ <with
+ variable="org.eclipse.amp.axf.ide.engine.state">
+ <equals
+ value="RUNNING">
+ </equals>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.amp.axf.ide.handlers.CloseHandler"
+ commandId="org.eclipse.amp.axf.ui.close">
+ <enabledWhen>
+ <with
+ variable="org.eclipse.amp.axf.ide.engine.state">
+ <or>
+ <equals
+ value="IDLE">
+ </equals>
+ <equals
+ value="ZOMBIE">
+ </equals>
+ </or>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.amp.axf.ide.handlers.StepHandler"
+ commandId="org.eclipse.amp.axf.ui.step">
+ <enabledWhen>
+ <with
+ variable="org.eclipse.amp.axf.ide.engine.state">
+ <equals
+ value="PAUSED">
+ </equals>
+ </with>
+ </enabledWhen>
+ </handler>
+ </extension>
+ <extension
+ point="org.eclipse.ui.services">
+ <sourceProvider
+ provider="org.eclipse.amp.axf.ide.EngineStateService">
+ <variable
+ name="org.eclipse.amp.axf.ide.engine.state"
+ priorityLevel="workbench">
+ </variable>
+ </sourceProvider>
+ </extension>
</plugin>
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/EngineStateService.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/EngineStateService.java
new file mode 100644
index 00000000..c0150011
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/EngineStateService.java
@@ -0,0 +1,173 @@
+package org.eclipse.amp.axf.ide;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.amp.axf.core.IEngine;
+import org.eclipse.amp.axf.core.ILifeCycleListener;
+import org.eclipse.amp.axf.core.IModel;
+import org.eclipse.amp.axf.core.IObservationProvider;
+import org.eclipse.amp.axf.core.LifeCycleState;
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * This {@link ISourceProvider} defines states that can be used to enable or
+ * disable handlers. The states are related to the execution of only the active
+ * {@link IModel}s. Execution states are {@link #IDLE}, {@link #RUNNING} and
+ * {@link #PAUSED}. This is a simplification of all {@link IEngine} states that
+ * are possible.
+ *
+ * @author jonas.ruettimann
+ */
+public class EngineStateService extends AbstractSourceProvider implements IModelWorkbenchListener, ILifeCycleListener {
+ public static final String ID = "org.eclipse.amp.axf.ide.engine.state";
+
+ /** Simulation has been stopped or not even started. */
+ public static final String IDLE = "IDLE";
+
+ /** Simulation is currently running. */
+ public static final String RUNNING = "RUNNING";
+
+ /** Simulation was running but has been set to pause. */
+ public static final String PAUSED = "PAUSED";
+
+ /** Simulation has stopped running, but the {@link Thread} is still alive. */
+ public static final String ZOMBIE = "ZOMBIE";
+
+ private IModel activeModel = null;
+
+ private String lastState;
+
+ public EngineStateService() {
+ ModelViewManager.getInstance().getManagerListeners().addModelManagerListener(this);
+ }
+
+ @Override
+ public Map<String, String> getCurrentState() {
+ Map<String, String> map = new HashMap<String, String>(1);
+ map.put(ID, getEngineState());
+ return map;
+ }
+
+ @Override
+ public String[] getProvidedSourceNames() {
+ return new String[] { ID };
+ }
+
+ private String getEngineState() {
+ if (activeModel != null && activeModel.getEngine() != null && !activeModel.getEngine().isCloseRequested()) {
+ if (activeModel.isPaused()) {
+ return PAUSED;
+ }
+ if (activeModel.isRunning()) {
+ return RUNNING;
+ }
+ if (activeModel.getEngine().isThreadAlive()) {
+ return ZOMBIE;
+ }
+ }
+
+ return IDLE; // used as default
+ }
+
+ @Override
+ public void stateChange(Object key, Object updated) {
+ if (key instanceof LifeCycleState) {
+ possibleStateChange();
+ }
+ }
+
+ private void possibleStateChange() {
+ String currentState = getEngineState();
+ if (!currentState.equals(lastState)) {
+ lastState = currentState;
+ notifyObservers(currentState);
+ }
+ }
+
+ /**
+ * This method has been extracted to be able to test notification behavior.
+ *
+ * @param currentState
+ */
+ protected void notifyObservers(String currentState) {
+ fireSourceChanged(ISources.WORKBENCH, ID, currentState);
+ }
+
+ @Override
+ public void dispose() {
+ unregister();
+ }
+
+ @Override
+ public void modelActivated(IModel newModel) {
+ unregister();
+
+ newModel.addModelListener(this);
+ activeModel = newModel;
+
+ possibleStateChange();
+ }
+
+ private void unregister() {
+ if (activeModel != null) {
+ activeModel.removeModelListener(this);
+ }
+ }
+
+ @Override
+ public void modelAdded(IModel model) {
+ }
+
+ @Override
+ public void modelRemoved(IModel model) {
+ }
+
+ @Override
+ public void viewAdded(IWorkbenchPart part) {
+ }
+
+ @Override
+ public void viewRemoved(IWorkbenchPart part) {
+ }
+
+ @Override
+ public void viewActivated(IWorkbenchPart part) {
+ }
+
+ @Override
+ public void observing(IObservationProvider observed) {
+ }
+
+ @Override
+ public void observeCreate(IObservationProvider observed) {
+ }
+
+ @Override
+ public void observeInitialize(IObservationProvider observed) {
+ }
+
+ @Override
+ public void observeStart(IObservationProvider observed) {
+ }
+
+ @Override
+ public void observeUpdate(IObservationProvider observed) {
+ }
+
+ @Override
+ public void observeStop(IObservationProvider observed) {
+ }
+
+ @Override
+ public void observationEnding(IObservationProvider observed) {
+ }
+
+ @Override
+ public void observationEnd(IObservationProvider observed) {
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/HandlerManager.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/HandlerManager.java
deleted file mode 100644
index ae85b95a..00000000
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/HandlerManager.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * <copyright>
- *
- * Copyright (c) 2009 Metascape, LLC.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Metascape - Initial API and Implementation
- *
- * </copyright>
- *
- */
-
-package org.eclipse.amp.axf.ide;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.amp.axf.ide.handlers.ModelRunHandler;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.handlers.IHandlerActivation;
-import org.eclipse.ui.handlers.IHandlerService;
-
-/**
- *
- * @author mparker
- *
- */
-public class HandlerManager {
-
- private IHandlerService handlerService;
-
- private List<IHandlerActivation> handlerActivations;
-
- private List<ModelRunHandler> handlers;
-
- public synchronized void activate() {
- handlerService = (IHandlerService) AXFWorkbenchPlugin.getDefault().getWorkbench()
- .getService(IHandlerService.class);
- handlerActivations = new ArrayList<IHandlerActivation>();
- handlers = new ArrayList<ModelRunHandler>();
- }
-
- public synchronized void deactivate() {
- if (handlerService != null) {
- handlerService.deactivateHandlers(handlerActivations);
- }
- }
-
- /**
- * Adds the handler.
- *
- * @param id the id
- * @param handler the handler
- */
- protected synchronized void addHandler(String id, final ModelRunHandler handler) {
- handlers.add(handler);
- handlerActivations.add(handlerService.activateHandler(id, handler));
- }
-
- public synchronized void notifyHandlers() {
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
- for (ModelRunHandler handler : handlers) {
- handler.notifyChange();
- }
- }
- });
- }
-}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/ModelViewManager.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/ModelViewManager.java
index 9d81a232..5fe76e28 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/ModelViewManager.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/ModelViewManager.java
@@ -24,14 +24,6 @@ import java.util.Map.Entry;
import org.eclipse.amp.axf.core.IEngine;
import org.eclipse.amp.axf.core.IModel;
import org.eclipse.amp.axf.core.IObservationProvider;
-import org.eclipse.amp.axf.ide.handlers.CloseHandler;
-import org.eclipse.amp.axf.ide.handlers.ModelRunHandler;
-import org.eclipse.amp.axf.ide.handlers.PauseHandler;
-import org.eclipse.amp.axf.ide.handlers.RestartHandler;
-import org.eclipse.amp.axf.ide.handlers.ResumeHandler;
-import org.eclipse.amp.axf.ide.handlers.StartHandler;
-import org.eclipse.amp.axf.ide.handlers.StepHandler;
-import org.eclipse.amp.axf.ide.handlers.StopHandler;
import org.eclipse.amp.axf.ide.view.StatusLineView;
import org.eclipse.amp.axf.view.IModelPart;
import org.eclipse.amp.axf.view.ModelInput;
@@ -60,53 +52,51 @@ import org.eclipse.ui.statushandlers.StatusManager;
@SuppressWarnings("restriction")
public class ModelViewManager implements IAdapterFactory {
+ public static final String EXECUTION_PERSPECTIVE_ID = "org.eclipse.amp.axf.ExecutionPerspective";
+
private static ModelViewManager instance;
- public static final String EXECUTION_PERSPECTIVE_ID = "org.eclipse.amp.axf.ExecutionPerspective";
+ boolean updated;
- /** The perspective ID to execute the simulation */
- private String executionPerspective = EXECUTION_PERSPECTIVE_ID;
+ String priorPerspectiveID;
- private IContextService contextService;
+ Map<IModel, List<IViewPart>> viewsForModel;
- private IContextActivation ideContext;
+ ModelManagerListeners managerListeners = new ModelManagerListeners();
- private IContextActivation partContext;
+ /** The perspective ID to execute the simulation */
+ String executionPerspective = EXECUTION_PERSPECTIVE_ID;
- List<IModel> models = new ArrayList<IModel>();
+ IContextService contextService;
- List<IViewPart> views = new ArrayList<IViewPart>();
+ IContextActivation ideContext;
- Map<IModel, IEngine> runnerForModel;
+ IContextActivation partContext;
- Map<IEngine, IModel> modelForRunner = new HashMap<IEngine, IModel>();
+ private List<IModel> models = new ArrayList<IModel>();
- Map<Object, IModel> modelForArbitrary = new HashMap<Object, IModel>();
+ private List<IViewPart> views = new ArrayList<IViewPart>();
- Map<IModel, List<IViewPart>> viewsForModel;
+ private Map<IModel, IEngine> runnerForModel;
- LifeCycleListeners activeModelListeners;
+ private Map<IEngine, IModel> modelForRunner = new HashMap<IEngine, IModel>();
- ModelManagerListeners managerListeners = new ModelManagerListeners();
+ private Map<Object, IModel> modelForArbitrary = new HashMap<Object, IModel>();
- HandlerManager handlers = new HandlerManager();
+ private LifeCycleListeners activeModelListeners = new LifeCycleListeners();
- IModel activeModel;
+ private IModel activeModel;
- IPartListener modelActivationListener;
+ private IPartListener modelActivationListener;
private IObservationProvider[] modelSlots = new IObservationProvider[16];
private SelectionSynchronizer editSelection;
- private String priorPerspectiveID;
-
private StatusLineView statusLineView;
private ModelManagerViewPart managerViewPart;
- boolean updated;
-
private ModelViewManager() {
}
@@ -223,7 +213,7 @@ public class ModelViewManager implements IAdapterFactory {
*
* @return the active model
*/
- public IObservationProvider getActiveModel() {
+ public IModel getActiveModel() {
return activeModel;
}
@@ -240,6 +230,7 @@ public class ModelViewManager implements IAdapterFactory {
}
final IModel oldModel = this.activeModel;
this.activeModel = newModel;
+
if (newModel != oldModel) {
getActiveModelListeners().replaceModel(oldModel, newModel);
if (newModel != null) {
@@ -525,34 +516,14 @@ public class ModelViewManager implements IAdapterFactory {
public void run() {
try {
contextService = (IContextService) wb.getService(IContextService.class);
- // for (Object o : contextService.getActiveContextIds()) {
- // System.err.pri0ntln(o);
- // contextService
- // contextService.deactivateContext();
- // }
ideContext = contextService.activateContext("org.eclipse.amp.axf.executionContext");
partContext = contextService.activateContext("org.eclipse.amp.axf.activeEditorContext");
- // contextService.deactivateContext(ideContext);
} catch (Exception e) {
throw new RuntimeException("Couldn't activate services.", e);
}
}
});
- handlers.activate();
- addHandler("org.eclipse.amp.axf.ui.start", new StartHandler());
- addHandler("org.eclipse.amp.axf.ui.stop", new StopHandler());
- addHandler("org.eclipse.amp.axf.ui.pause", new PauseHandler());
- addHandler("org.eclipse.amp.axf.ui.resume", new ResumeHandler());
- addHandler("org.eclipse.amp.axf.ui.restart", new RestartHandler());
- addHandler("org.eclipse.amp.axf.ui.close", new CloseHandler());
- addHandler("org.eclipse.amp.axf.ui.step", new StepHandler());
- }
-
- public void addHandler(String id, ModelRunHandler handler) {
- handlers.addHandler(id, handler);
- getActiveModelListeners().addListener(handler);
- getManagerListeners().addModelManagerListener(handler);
}
private void activatePerspective(final IWorkbench wb, final String perspectiveID, final boolean editors) {
@@ -582,7 +553,6 @@ public class ModelViewManager implements IAdapterFactory {
contextService.deactivateContext(ideContext);
contextService.deactivateContext(partContext);
}
- handlers.deactivate();
}
});
getPage().removePartListener(modelActivationListener);
@@ -656,10 +626,6 @@ public class ModelViewManager implements IAdapterFactory {
return activeModelListeners;
}
- public HandlerManager getHandlers() {
- return handlers;
- }
-
/**
* @return the managerViewPart
*/
@@ -689,4 +655,5 @@ public class ModelViewManager implements IAdapterFactory {
public void setExecutionPerspective(String executionPerspective) {
this.executionPerspective = executionPerspective;
}
+
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/CloseHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/CloseHandler.java
index 6127b419..2ad68ad3 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/CloseHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/CloseHandler.java
@@ -17,25 +17,20 @@ package org.eclipse.amp.axf.ide.handlers;
import org.eclipse.amp.axf.core.EngineControl;
-// TODO: Auto-generated Javadoc
/**
- * The Class CloseHandler.
+ * Stop and close the simulation.
+ *
+ * @author jonas.ruettimann
*/
public class CloseHandler extends ModelRunHandler {
- /**
- * Instantiates a new close handler.
- */
- public CloseHandler() {
- super(EngineControl.CLOSE);
- }
+ public CloseHandler() {
+ super(EngineControl.CLOSE);
+ }
- /**
- * @return
- * @see org.eclipse.amp.axf.ide.handlers.ModelRunHandler#isEnabled()
- */
- public boolean isEnabled() {
- return super.isEnabled() || getRunner() != null && getRunner().getModelThread() != null
- && getRunner().getModelThread().isAlive();
- }
+ @Override
+ public boolean isEnabled() {
+ assert super.isEnabled() || getRunner() != null && getRunner().isThreadAlive() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ModelRunHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ModelRunHandler.java
index 3971458e..121da599 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ModelRunHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ModelRunHandler.java
@@ -33,82 +33,57 @@ import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPart;
/**
- * The Class ModelRunHandler.
+ * Super class for all {@link AbstractHandler}s to control the {@link IEngine}
+ * execution.
+ *
+ * @author jonas.ruettimann
*/
public abstract class ModelRunHandler extends AbstractHandler implements ILifeCycleListener, IModelWorkbenchListener {
- private IModel model;
-
private EngineControl control;
private IStateListener delegate;
- /**
- * Instantiates a new model run handler.
- *
- * @param control
- * the control
- */
public ModelRunHandler(EngineControl control) {
this.control = control;
delegate = new LifecycleObservationAdapter(this);
}
- /**
- * @param event
- * @return
- * @throws ExecutionException
- * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
- */
public Object execute(ExecutionEvent event) throws ExecutionException {
getRunner().control(control);
- ModelViewManager.getInstance().getHandlers().notifyHandlers();
return null;
}
- /**
- * Gets the runner.
- *
- * @return the runner
- */
- public IEngine getRunner() {
- return model != null ? model.getEngine() : null;
+ protected IEngine getRunner() {
+ IModel model = ModelViewManager.getInstance().getActiveModel();
+ if (model == null) {
+ return null;
+ }
+ return model.getEngine();
}
- /**
- * @return
- * @see org.eclipse.core.commands.AbstractHandler#isEnabled()
- */
+ @Override
public boolean isEnabled() {
- return getRunner() != null && !getRunner().isCloseRequested();
+ assert getRunner() != null && !getRunner().isCloseRequested() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
}
- /**
- * Notify change.
- */
public void notifyChange() {
// its possible we've already left workbench
if (AXFWorkbenchPlugin.getDefault() != null) {
IWorkbench workbench = AXFWorkbenchPlugin.getDefault().getWorkbench();
- if (model != null && workbench.getDisplay() != null && !workbench.getDisplay().isDisposed()) {
+ if (workbench.getDisplay() != null && !workbench.getDisplay().isDisposed()) {
workbench.getDisplay().asyncExec(new Runnable() {
public void run() {
- fireHandlerChanged(new HandlerEvent(ModelRunHandler.this, true, false));
+ fireChangeEvent();
}
});
}
}
}
- public synchronized void observing(IObservationProvider model) {
- this.model = (IModel) model;
- }
-
- public synchronized void observationEnd(IObservationProvider model) {
- // we may have a lagging model notification from another model
- if (model == this.model) {
- this.model = null;
- }
+ protected void fireChangeEvent() {
+ fireHandlerChanged(new HandlerEvent(this, true, false));
}
public void stateChange(Object key, Object updated) {
@@ -117,10 +92,15 @@ public abstract class ModelRunHandler extends AbstractHandler implements ILifeCy
}
public synchronized void modelActivated(IModel model) {
- this.model = model;
notifyChange();
}
+ public synchronized void observing(IObservationProvider model) {
+ }
+
+ public synchronized void observationEnd(IObservationProvider model) {
+ }
+
public void modelAdded(IModel model) {
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/PauseHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/PauseHandler.java
index 25549ef6..566121b8 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/PauseHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/PauseHandler.java
@@ -12,30 +12,32 @@
*
* </copyright>
*
-*/
+ */
package org.eclipse.amp.axf.ide.handlers;
import org.eclipse.amp.axf.core.EngineControl;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
-// TODO: Auto-generated Javadoc
/**
- * The Class PauseHandler.
+ * Pause the simulation.
+ *
+ * @author jonas.ruettimann
*/
public class PauseHandler extends ModelRunHandler {
- /**
- * Instantiates a new pause handler.
- */
- public PauseHandler() {
- super(EngineControl.PAUSE);
- }
+ public PauseHandler() {
+ super(EngineControl.PAUSE);
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ return super.execute(event);
+ }
- /**
- * @return
- * @see org.eclipse.amp.axf.ide.handlers.ModelRunHandler#isEnabled()
- */
- @Override
- public boolean isEnabled() {
- return super.isEnabled() && !getRunner().isPaused();
- }
+ @Override
+ public boolean isEnabled() {
+ assert !getRunner().isPaused() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/RestartHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/RestartHandler.java
index a5658a5e..9f281d71 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/RestartHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/RestartHandler.java
@@ -17,25 +17,20 @@ package org.eclipse.amp.axf.ide.handlers;
import org.eclipse.amp.axf.core.EngineControl;
-// TODO: Auto-generated Javadoc
/**
- * The Class RestartHandler.
+ * Restart the simulation.
+ *
+ * @author jonas.ruettimann
*/
public class RestartHandler extends ModelRunHandler {
- /**
- * Instantiates a new restart handler.
- */
- public RestartHandler() {
- super(EngineControl.RESTART);
- }
+ public RestartHandler() {
+ super(EngineControl.RESTART);
+ }
- /**
- * @return
- * @see org.eclipse.amp.axf.ide.handlers.ModelRunHandler#isEnabled()
- */
- public boolean isEnabled() {
- // TODO Auto-generated method stub
- return super.isEnabled() && getRunner().isRunning();
- }
+ @Override
+ public boolean isEnabled() {
+ assert getRunner().isRunning() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ResumeHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ResumeHandler.java
index 5834cdf4..fd9cb112 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ResumeHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/ResumeHandler.java
@@ -12,31 +12,25 @@
*
* </copyright>
*
-*/
+ */
package org.eclipse.amp.axf.ide.handlers;
import org.eclipse.amp.axf.core.EngineControl;
-// TODO: Auto-generated Javadoc
/**
- * The Class ResumeHandler.
+ * Resume the simulation execution.
+ *
+ * @author jonas.ruettimann
*/
public class ResumeHandler extends ModelRunHandler {
- /**
- * Instantiates a new resume handler.
- */
- public ResumeHandler() {
- super(EngineControl.RESUME);
- }
+ public ResumeHandler() {
+ super(EngineControl.RESUME);
+ }
- /**
- * @return
- * @see org.eclipse.amp.axf.ide.handlers.ModelRunHandler#isEnabled()
- */
- @Override
- public boolean isEnabled() {
- // TODO Auto-generated method stub
- return super.isEnabled() && getRunner().isPaused();
- }
+ @Override
+ public boolean isEnabled() {
+ assert getRunner().isPaused() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StartHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StartHandler.java
index 4f179b87..4d611873 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StartHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StartHandler.java
@@ -12,29 +12,25 @@
*
* </copyright>
*
-*/
+ */
package org.eclipse.amp.axf.ide.handlers;
import org.eclipse.amp.axf.core.EngineControl;
-// TODO: Auto-generated Javadoc
/**
- * The Class StartHandler.
+ * Start the simulation.
+ *
+ * @author jonas.ruettimann
*/
public class StartHandler extends ModelRunHandler {
- /**
- * Instantiates a new start handler.
- */
- public StartHandler() {
- super(EngineControl.START);
- }
+ public StartHandler() {
+ super(EngineControl.START);
+ }
- /**
- * @return
- * @see org.eclipse.amp.axf.ide.handlers.ModelRunHandler#isEnabled()
- */
- public boolean isEnabled() {
- return super.isEnabled() && !getRunner().isRunning();
- }
+ @Override
+ public boolean isEnabled() {
+ assert !getRunner().isRunning() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StepHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StepHandler.java
index 57f60cb6..2eed6b86 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StepHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StepHandler.java
@@ -12,29 +12,25 @@
*
* </copyright>
*
-*/
+ */
package org.eclipse.amp.axf.ide.handlers;
import org.eclipse.amp.axf.core.EngineControl;
-// TODO: Auto-generated Javadoc
/**
- * The Class StepHandler.
+ * Run a single time step of the simulation.
+ *
+ * @author jonas.ruettimann
*/
public class StepHandler extends ModelRunHandler {
- /**
- * Instantiates a new step handler.
- */
- public StepHandler() {
- super(EngineControl.STEP);
- }
+ public StepHandler() {
+ super(EngineControl.STEP);
+ }
- /**
- * @return
- * @see org.eclipse.amp.axf.ide.handlers.ModelRunHandler#isEnabled()
- */
- public boolean isEnabled() {
- return super.isEnabled() && getRunner().isRunning() && getRunner().isPaused();
- }
+ @Override
+ public boolean isEnabled() {
+ assert getRunner().isRunning() && getRunner().isPaused() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StopHandler.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StopHandler.java
index 7c2ea532..b99c90fa 100644
--- a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StopHandler.java
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/src/org/eclipse/amp/axf/ide/handlers/StopHandler.java
@@ -12,29 +12,25 @@
*
* </copyright>
*
-*/
+ */
package org.eclipse.amp.axf.ide.handlers;
import org.eclipse.amp.axf.core.EngineControl;
-// TODO: Auto-generated Javadoc
/**
- * The Class StopHandler.
+ * Stop the simulation.
+ *
+ * @author jonas.ruettimann
*/
public class StopHandler extends ModelRunHandler {
- /**
- * Instantiates a new stop handler.
- */
- public StopHandler() {
- super(EngineControl.STOP);
- }
+ public StopHandler() {
+ super(EngineControl.STOP);
+ }
- /**
- * @return
- * @see org.eclipse.amp.axf.ide.handlers.ModelRunHandler#isEnabled()
- */
- public boolean isEnabled() {
- return super.isEnabled() && getRunner().isRunning();
- }
+ @Override
+ public boolean isEnabled() {
+ assert getRunner().isRunning() : "Obviously, this command was declarately enabled not the way it's ment to be.";
+ return super.isEnabled();
+ }
}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/EngineStateServiceTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/EngineStateServiceTest.java
new file mode 100644
index 00000000..12dbbd27
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/EngineStateServiceTest.java
@@ -0,0 +1,369 @@
+package org.eclipse.amp.axf.ide;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.amp.axf.core.EngineControl;
+import org.eclipse.amp.axf.core.IEngine;
+import org.eclipse.amp.axf.core.ILifeCycleListener;
+import org.eclipse.amp.axf.core.IModel;
+import org.eclipse.amp.axf.core.IObservationProvider;
+import org.eclipse.amp.axf.core.LifeCycleState;
+import org.eclipse.amp.axf.time.ITimeGranularity;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.services.ISourceProviderService;
+import org.junit.Before;
+import org.junit.Test;
+
+public class EngineStateServiceTest {
+
+ private EngineStateServiceMock classToTest;
+
+ @Before
+ public void setUp() {
+ classToTest = new EngineStateServiceMock();
+ }
+
+ /**
+ * Was the {@link EngineStateService} registered by the plugin.xml?
+ */
+ @Test
+ public void testWasRegisteredByPluginXML() {
+ ISourceProviderService service = (ISourceProviderService) PlatformUI.getWorkbench().getService(ISourceProviderService.class);
+ ISourceProvider sourceProvider = service.getSourceProvider(EngineStateService.ID);
+ assertTrue(sourceProvider instanceof EngineStateService);
+ }
+
+ /**
+ * Does the {@link EngineStateService} register itself as a
+ * {@link IModelWorkbenchListener} on the {@link ModelManagerListeners}?
+ */
+ @Test
+ public void testEngineStateService() {
+ ModelViewManager.getInstance().getManagerListeners().manangerListeners.contains(classToTest);
+ }
+
+ /**
+ * The activation of an {@link IModel} should cause the
+ * {@link EngineStateService} to be registered as an
+ * {@link ILifeCycleListener} on the active {@link IModel}.
+ */
+ @Test
+ public void testModelActivated() {
+ IModel modelA = new DummyModel();
+ IModel modelB = new DummyModel();
+
+ // not registered:
+ assertFalse(modelA.getModelListeners().contains(classToTest));
+ assertFalse(modelB.getModelListeners().contains(classToTest));
+
+ // register to modelA:
+ classToTest.modelActivated(modelA);
+ assertTrue(modelA.getModelListeners().contains(classToTest));
+ assertFalse(modelB.getModelListeners().contains(classToTest));
+
+ // unregister at modelA, register at modelB:
+ classToTest.modelActivated(modelB);
+ assertTrue(modelB.getModelListeners().contains(classToTest));
+ assertFalse(modelA.getModelListeners().contains(classToTest));
+ }
+
+ /**
+ * Without an active {@link IModel} the default state
+ * {@link EngineStateService#IDLE} should be returned. Otherwise the state of
+ * the {@link IModel} matters.
+ */
+ @Test
+ public void testGetCurrentState() {
+ assertEquals(EngineStateService.IDLE, classToTest.getCurrentState().get(EngineStateService.ID));
+
+ DummyModel model = new DummyModel();
+ classToTest.modelActivated(model);
+ assertEquals(EngineStateService.IDLE, classToTest.getCurrentState().get(EngineStateService.ID));
+
+ model.running = true;
+ assertEquals(EngineStateService.RUNNING, classToTest.getCurrentState().get(EngineStateService.ID));
+
+ model.getEngine().closeRequested = true;
+ assertEquals(EngineStateService.IDLE, classToTest.getCurrentState().get(EngineStateService.ID));
+ model.getEngine().closeRequested = false;
+
+ model.paused = true;
+ assertEquals(EngineStateService.PAUSED, classToTest.getCurrentState().get(EngineStateService.ID));
+
+ model.paused = false;
+ assertEquals(EngineStateService.RUNNING, classToTest.getCurrentState().get(EngineStateService.ID));
+
+ model.running = false;
+ assertEquals(EngineStateService.IDLE, classToTest.getCurrentState().get(EngineStateService.ID));
+
+ model.getEngine().alive = true;
+ assertEquals(EngineStateService.ZOMBIE, classToTest.getCurrentState().get(EngineStateService.ID));
+ }
+
+ /**
+ * Only a changing state should lead to firing an event.
+ */
+ @Test
+ public void testStateChange() {
+ DummyModel model = new DummyModel();
+
+ // First state change ever; this should cause a notification:
+ classToTest.modelActivated(model);
+ assertTrue(classToTest.isNotificationFired());
+
+ // Not another notification:
+ classToTest.stateChange(LifeCycleState.UPDATE, "");
+ assertFalse(classToTest.isNotificationFired());
+
+ // Changing the state should cause notification:
+ model.running = true;
+ classToTest.stateChange(LifeCycleState.UPDATE, "");
+ assertTrue(classToTest.isNotificationFired());
+
+ // Not another notification:
+ classToTest.stateChange(LifeCycleState.UPDATE, "");
+ assertFalse(classToTest.isNotificationFired());
+
+ // A new model that is different should cause notification:
+ DummyModel differentModel = new DummyModel();
+ classToTest.modelActivated(differentModel);
+ assertTrue(classToTest.isNotificationFired());
+
+ // But not an equal one:
+ DummyModel equalModel = new DummyModel();
+ classToTest.modelActivated(equalModel);
+ assertFalse(classToTest.isNotificationFired());
+ }
+
+ /**
+ * Disposing the {@link EngineStateService} should unregister itself at the
+ * active {@link IModel}.
+ */
+ @Test
+ public void testDispose() {
+ IModel modelA = new DummyModel();
+ assertFalse(modelA.getModelListeners().contains(classToTest));
+
+ classToTest.modelActivated(modelA);
+ assertTrue(modelA.getModelListeners().contains(classToTest));
+
+ classToTest.dispose();
+ assertFalse(modelA.getModelListeners().contains(classToTest));
+ }
+
+ /**
+ * Disposing the {@link EngineStateService} without an active {@link IModel}
+ * should not lead to an {@link Exception}.
+ */
+ @Test
+ public void testDispose_noActiveModel() {
+ try {
+ classToTest.dispose();
+ assertTrue(true);
+
+ } catch (Exception e) {
+ fail("No active model causes an Exception: " + e.getMessage());
+ }
+ }
+
+ private class EngineStateServiceMock extends EngineStateService {
+ private boolean notificationFired = false;
+
+ public EngineStateServiceMock() {
+ }
+
+ public boolean isNotificationFired() {
+ return notificationFired;
+ }
+
+ @Override
+ public void stateChange(Object key, Object updated) {
+ notificationFired = false;
+ super.stateChange(key, updated);
+ }
+
+ @Override
+ public void modelActivated(IModel newModel) {
+ notificationFired = false;
+ super.modelActivated(newModel);
+ }
+
+ @Override
+ protected void notifyObservers(String currentState) {
+ notificationFired = true;
+ super.notifyObservers(currentState);
+ }
+ }
+
+ private class DummyModel implements IModel {
+
+ boolean running = false;
+
+ boolean paused = false;
+
+ private List<ILifeCycleListener> listeners = new ArrayList<ILifeCycleListener>();
+
+ private DummyEngine engine = new DummyEngine();
+
+ public DummyModel() {
+ }
+
+ @Override
+ public boolean isCreated() {
+ return false;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return false;
+ }
+
+ @Override
+ public boolean isStopped() {
+ return false;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return running;
+ }
+
+ @Override
+ public boolean isPaused() {
+ return paused;
+ }
+
+ @Override
+ public boolean isActive() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnding() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnded() {
+ return false;
+ }
+
+ @Override
+ public void addModelListener(ILifeCycleListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public Collection<ILifeCycleListener> getModelListeners() {
+ return listeners;
+ }
+
+ @Override
+ public void removeModelListener(ILifeCycleListener listener) {
+ listeners.remove(listener);
+ }
+
+ @Override
+ public String getTimeDescription() {
+ return null;
+ }
+
+ @Override
+ public DummyEngine getEngine() {
+ return engine;
+ }
+
+ @Override
+ public Object getRoot() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public int getPeriod() {
+ return 0;
+ }
+
+ @Override
+ public int getStopPeriod() {
+ return 0;
+ }
+ }
+
+ private class DummyEngine implements IEngine {
+ boolean closeRequested = false;
+
+ boolean alive = false;
+
+ public DummyEngine() {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public void closeFinally() {
+ }
+
+ @Override
+ public boolean isCloseRequested() {
+ return closeRequested;
+ }
+
+ @Override
+ public boolean isThreadAlive() {
+ return alive;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return false;
+ }
+
+ @Override
+ public boolean isPaused() {
+ return false;
+ }
+
+ @Override
+ public void stop() {
+ }
+
+ @Override
+ public void control(EngineControl ModelControl) {
+ }
+
+ @Override
+ public void observationComplete(ILifeCycleListener observer) {
+ }
+
+ @Override
+ public IObservationProvider getModel() {
+ return null;
+ }
+
+ @Override
+ public void setUpdateGranularity(ITimeGranularity granularity) {
+ }
+
+ @Override
+ public ITimeGranularity getUpdateGranularity() {
+ return null;
+ }
+
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/CloseHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/CloseHandlerTest.java
new file mode 100644
index 00000000..357245be
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/CloseHandlerTest.java
@@ -0,0 +1,20 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+public class CloseHandlerTest extends ModelRunHandlerTest {
+
+ @Override
+ protected String getCommandToTestId() {
+ return "org.eclipse.amp.axf.ui.close";
+ }
+
+ @Override
+ protected boolean needsRunningStateToBeEnabled() {
+ return false;
+ }
+
+ @Override
+ protected boolean needsPauseStateToBeEnabled() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ModelRunHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ModelRunHandlerTest.java
new file mode 100644
index 00000000..f41def77
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ModelRunHandlerTest.java
@@ -0,0 +1,243 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+
+import org.eclipse.amp.axf.core.EngineControl;
+import org.eclipse.amp.axf.core.IEngine;
+import org.eclipse.amp.axf.core.ILifeCycleListener;
+import org.eclipse.amp.axf.core.IModel;
+import org.eclipse.amp.axf.core.IObservationProvider;
+import org.eclipse.amp.axf.core.LifeCycleState;
+import org.eclipse.amp.axf.ide.EngineStateService;
+import org.eclipse.amp.axf.ide.ModelViewManager;
+import org.eclipse.amp.axf.time.ITimeGranularity;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.services.ISourceProviderService;
+import org.junit.Before;
+import org.junit.Test;
+
+public abstract class ModelRunHandlerTest {
+
+ private DummyModel model;
+
+ private EngineStateService stateService;
+
+ private IHandlerService handlerService;
+
+ protected abstract String getCommandToTestId();
+
+ protected abstract boolean needsRunningStateToBeEnabled();
+
+ protected abstract boolean needsPauseStateToBeEnabled();
+
+ @Before
+ public void setUp() {
+ model = new DummyModel();
+
+ ISourceProviderService sourceProviderService = (ISourceProviderService) PlatformUI.getWorkbench().getService(ISourceProviderService.class);
+ stateService = (EngineStateService) sourceProviderService.getSourceProvider(EngineStateService.ID);
+
+ handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
+
+ ModelViewManager.getInstance().getModels().add(model);
+ ModelViewManager.getInstance().setActiveModel(model);
+ }
+
+ @Test
+ public void testEnabled() {
+ model.running = needsRunningStateToBeEnabled();
+ model.paused = needsPauseStateToBeEnabled();
+ stateService.stateChange(LifeCycleState.UPDATE, "");
+
+ try {
+ handlerService.executeCommand(getCommandToTestId(), null);
+ assertTrue(true); // There should not be an Exception.
+
+ } catch (Exception e) {
+ fail("Executing " + getCommandToTestId() + " caused an Exception:" + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testDisabled() throws ExecutionException, NotDefinedException, NotHandledException {
+ model.running = !needsRunningStateToBeEnabled();
+ model.paused = !needsPauseStateToBeEnabled();
+ stateService.stateChange(LifeCycleState.UPDATE, "");
+
+ try {
+ handlerService.executeCommand(getCommandToTestId(), null);
+ fail(getCommandToTestId() + " should not be enabled if model is not running.");
+
+ } catch (NotEnabledException e) {
+ assertTrue(true); // This is expected to happen.
+ }
+ }
+
+ private class DummyModel implements IModel {
+
+ boolean running = false;
+
+ boolean paused = false;
+
+ private DummyEngine engine = new DummyEngine(this);
+
+ public DummyModel() {
+ }
+
+ @Override
+ public boolean isCreated() {
+ return false;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return false;
+ }
+
+ @Override
+ public boolean isStopped() {
+ return false;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return running;
+ }
+
+ @Override
+ public boolean isPaused() {
+ return paused;
+ }
+
+ @Override
+ public boolean isActive() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnding() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnded() {
+ return false;
+ }
+
+ @Override
+ public void addModelListener(ILifeCycleListener listener) {
+ }
+
+ @Override
+ public Collection<ILifeCycleListener> getModelListeners() {
+ return null;
+ }
+
+ @Override
+ public void removeModelListener(ILifeCycleListener listener) {
+ }
+
+ @Override
+ public String getTimeDescription() {
+ return null;
+ }
+
+ @Override
+ public DummyEngine getEngine() {
+ return engine;
+ }
+
+ @Override
+ public Object getRoot() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public int getPeriod() {
+ return 0;
+ }
+
+ @Override
+ public int getStopPeriod() {
+ return 0;
+ }
+ }
+
+ private class DummyEngine implements IEngine {
+
+ private DummyModel dummyModel;
+
+ public DummyEngine(DummyModel model) {
+ this.dummyModel = model;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public void closeFinally() {
+ }
+
+ @Override
+ public boolean isCloseRequested() {
+ return false;
+ }
+
+ @Override
+ public boolean isThreadAlive() {
+ return false;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return getModel().isRunning();
+ }
+
+ @Override
+ public boolean isPaused() {
+ return getModel().isPaused();
+ }
+
+ @Override
+ public void stop() {
+ }
+
+ @Override
+ public void control(EngineControl ModelControl) {
+ }
+
+ @Override
+ public void observationComplete(ILifeCycleListener observer) {
+ }
+
+ @Override
+ public IObservationProvider getModel() {
+ return dummyModel;
+ }
+
+ @Override
+ public void setUpdateGranularity(ITimeGranularity granularity) {
+ }
+
+ @Override
+ public ITimeGranularity getUpdateGranularity() {
+ return null;
+ }
+
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/PauseHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/PauseHandlerTest.java
new file mode 100644
index 00000000..5fd95fa9
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/PauseHandlerTest.java
@@ -0,0 +1,20 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+public class PauseHandlerTest extends ModelRunHandlerTest {
+
+ @Override
+ protected String getCommandToTestId() {
+ return "org.eclipse.amp.axf.ui.pause";
+ }
+
+ @Override
+ protected boolean needsRunningStateToBeEnabled() {
+ return true;
+ }
+
+ @Override
+ protected boolean needsPauseStateToBeEnabled() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/RestartHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/RestartHandlerTest.java
new file mode 100644
index 00000000..b256ddaf
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/RestartHandlerTest.java
@@ -0,0 +1,20 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+public class RestartHandlerTest extends ModelRunHandlerTest {
+
+ @Override
+ protected String getCommandToTestId() {
+ return "org.eclipse.amp.axf.ui.restart";
+ }
+
+ @Override
+ protected boolean needsRunningStateToBeEnabled() {
+ return true;
+ }
+
+ @Override
+ protected boolean needsPauseStateToBeEnabled() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ResumeHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ResumeHandlerTest.java
new file mode 100644
index 00000000..cb8dd378
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/ResumeHandlerTest.java
@@ -0,0 +1,20 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+public class ResumeHandlerTest extends ModelRunHandlerTest {
+
+ @Override
+ protected String getCommandToTestId() {
+ return "org.eclipse.amp.axf.ui.resume";
+ }
+
+ @Override
+ protected boolean needsRunningStateToBeEnabled() {
+ return true;
+ }
+
+ @Override
+ protected boolean needsPauseStateToBeEnabled() {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StartHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StartHandlerTest.java
new file mode 100644
index 00000000..23d8afc8
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StartHandlerTest.java
@@ -0,0 +1,20 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+public class StartHandlerTest extends ModelRunHandlerTest {
+
+ @Override
+ protected String getCommandToTestId() {
+ return "org.eclipse.amp.axf.ui.start";
+ }
+
+ @Override
+ protected boolean needsRunningStateToBeEnabled() {
+ return false;
+ }
+
+ @Override
+ protected boolean needsPauseStateToBeEnabled() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StepHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StepHandlerTest.java
new file mode 100644
index 00000000..22ab04d0
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StepHandlerTest.java
@@ -0,0 +1,20 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+public class StepHandlerTest extends ModelRunHandlerTest {
+
+ @Override
+ protected String getCommandToTestId() {
+ return "org.eclipse.amp.axf.ui.step";
+ }
+
+ @Override
+ protected boolean needsRunningStateToBeEnabled() {
+ return true;
+ }
+
+ @Override
+ protected boolean needsPauseStateToBeEnabled() {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StopHandlerTest.java b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StopHandlerTest.java
new file mode 100644
index 00000000..256e49b8
--- /dev/null
+++ b/org.eclipse.amp.axf/plugins/org.eclipse.amp.axf.ide/test/org/eclipse/amp/axf/ide/handlers/StopHandlerTest.java
@@ -0,0 +1,20 @@
+package org.eclipse.amp.axf.ide.handlers;
+
+public class StopHandlerTest extends ModelRunHandlerTest {
+
+ @Override
+ protected String getCommandToTestId() {
+ return "org.eclipse.amp.axf.ui.stop";
+ }
+
+ @Override
+ protected boolean needsRunningStateToBeEnabled() {
+ return true;
+ }
+
+ @Override
+ protected boolean needsPauseStateToBeEnabled() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ModelWrapperScapeListener.java b/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ModelWrapperScapeListener.java
index 4f33586e..1e461c07 100644
--- a/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ModelWrapperScapeListener.java
+++ b/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ModelWrapperScapeListener.java
@@ -12,7 +12,7 @@
*
* </copyright>
*
-*/
+ */
package org.eclipse.amp.escape.ascape.wrap;
import java.util.TooManyListenersException;
@@ -25,155 +25,121 @@ import org.eclipse.amp.axf.core.IModel;
import org.eclipse.amp.axf.core.IStateListener;
import org.eclipse.amp.axf.core.LifeCycleState;
-// TODO: Auto-generated Javadoc
/**
- * The listener interface for receiving modelWrapperScape events. The class that is interested in processing a
- * modelWrapperScape event implements this interface, and the object created with that class is registered with a
- * component using the component's <code>addModelWrapperScapeListener<code> method. When
+ * The listener interface for receiving modelWrapperScape events. The class that
+ * is interested in processing a modelWrapperScape event implements this
+ * interface, and the object created with that class is registered with a
+ * component using the component's
+ * <code>addModelWrapperScapeListener<code> method. When
* the modelWrapperScape event occurs, that object's appropriate
* method is invoked.
*
- * @see ModelWrapperScapeEvent
+ * @see ScapeEvent
*/
public class ModelWrapperScapeListener extends DefaultScapeListener {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- IModel model;
- IStateListener wrapped;
-
- /**
- * Instantiates a new model wrapper scape listener.
- *
- * @param model the model
- * @param scape the scape
- * @param wrapped the wrapped
- */
- public ModelWrapperScapeListener(IModel model, Scape scape, ILifeCycleListener wrapped) {
- this.model = model;
- this.scape = scape;
- this.wrapped = wrapped;
- if (model == null) {
- throw new RuntimeException("Model cannot be null.");
- }
- if (scape == null) {
- throw new RuntimeException("Scape cannot be null.");
- }
- if (wrapped == null) {
- throw new RuntimeException("Wrapped listener cannot be null." + wrapped + " for " + scape);
- }
- }
-
- /**
- * @param scapeEvent
- * @throws TooManyListenersException
- * @see org.ascape.model.event.DefaultScapeListener#scapeAdded(org.ascape.model.event.ScapeEvent)
- */
- public void scapeAdded(ScapeEvent scapeEvent) throws TooManyListenersException {
- wrapped.stateChange(LifeCycleState.OBSERVED, model);
- super.scapeAdded(scapeEvent);
- }
-
- /**
- * @param scapeEvent
- * @see org.ascape.model.event.DefaultScapeListener#scapeClosing(org.ascape.model.event.ScapeEvent)
- */
- public void scapeClosing(ScapeEvent scapeEvent) {
- wrapped.stateChange(LifeCycleState.ENDING, model);
- super.scapeClosing(scapeEvent);
- }
-
- /**
- * @param scapeEvent
- * @see org.ascape.model.event.DefaultScapeListener#scapeInitialized(org.ascape.model.event.ScapeEvent)
- */
- public void scapeInitialized(ScapeEvent scapeEvent) {
- wrapped.stateChange(LifeCycleState.INITIALIZE, model);
- }
-
- /**
- * @param scapeEvent
- * @see org.ascape.model.event.DefaultScapeListener#scapeIterated(org.ascape.model.event.ScapeEvent)
- */
- public void scapeIterated(ScapeEvent scapeEvent) {
- wrapped.stateChange(LifeCycleState.UPDATE, model);
- }
-
- /**
- * @param scapeEvent
- * @see org.ascape.model.event.DefaultScapeListener#scapeRemoved(org.ascape.model.event.ScapeEvent)
- */
- public void scapeRemoved(ScapeEvent scapeEvent) {
- wrapped.stateChange(LifeCycleState.END, model);
- super.scapeRemoved(scapeEvent);
- }
-
- /**
- * @param scapeEvent
- * @see org.ascape.model.event.DefaultScapeListener#scapeSetup(org.ascape.model.event.ScapeEvent)
- */
- public void scapeSetup(ScapeEvent scapeEvent) {
- wrapped.stateChange(LifeCycleState.CREATE, model);
- }
-
- /**
- * @param scapeEvent
- * @see org.ascape.model.event.DefaultScapeListener#scapeStarted(org.ascape.model.event.ScapeEvent)
- */
- public void scapeStarted(ScapeEvent scapeEvent) {
- wrapped.stateChange(LifeCycleState.START, model);
- }
-
- /**
- * @param scapeEvent
- * @see org.ascape.model.event.DefaultScapeListener#scapeStopped(org.ascape.model.event.ScapeEvent)
- */
- public void scapeStopped(ScapeEvent scapeEvent) {
- wrapped.stateChange(LifeCycleState.STOP, model);
- }
-
- /**
- * @return
- * @see org.ascape.model.event.DefaultScapeListener#getScape()
- */
- public Scape getScape() {
- return scape;
- }
-
- /**
- * @return
- * @see org.ascape.model.event.DefaultScapeListener#isGraphic()
- */
- public boolean isGraphic() {
- return false;
- }
-
- /**
- * @return
- * @see org.ascape.model.event.DefaultScapeListener#isLifeOfScape()
- */
- public boolean isLifeOfScape() {
- return false;
- }
-
- /**
- * @return
- * @see org.ascape.model.event.DefaultScapeListener#getName()
- */
- public String getName() {
- return wrapped.toString() + " Wrapped";
- }
-
- /**
- * Clones this object.
- *
- * @return the object
- */
- public Object clone() {
- ModelWrapperScapeListener clone = (ModelWrapperScapeListener) super.clone();
- return clone;
- }
+ private static final long serialVersionUID = 1L;
+
+ private IModel model;
+
+ private IStateListener wrapped;
+
+ /**
+ * Instantiates a new model wrapper scape listener.
+ *
+ * @param model
+ * the model
+ * @param scape
+ * the scape
+ * @param wrapped
+ * the wrapped
+ */
+ public ModelWrapperScapeListener(IModel model, Scape scape, ILifeCycleListener wrapped) {
+ this.model = model;
+ this.scape = scape;
+ this.wrapped = wrapped;
+ if (model == null) {
+ throw new RuntimeException("Model cannot be null.");
+ }
+ if (scape == null) {
+ throw new RuntimeException("Scape cannot be null.");
+ }
+ if (wrapped == null) {
+ throw new RuntimeException("Wrapped listener cannot be null." + wrapped + " for " + scape);
+ }
+ }
+
+ @Override
+ public void scapeAdded(ScapeEvent scapeEvent) throws TooManyListenersException {
+ wrapped.stateChange(LifeCycleState.OBSERVED, model);
+ super.scapeAdded(scapeEvent);
+ }
+
+ @Override
+ public void scapeClosing(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.ENDING, model);
+ super.scapeClosing(scapeEvent);
+ }
+
+ @Override
+ public void scapeInitialized(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.INITIALIZE, model);
+ }
+
+ @Override
+ public void scapeIterated(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.UPDATE, model);
+ }
+
+ @Override
+ public void scapePaused(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.PAUSED, model);
+ }
+
+ @Override
+ public void scapeRemoved(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.END, model);
+ super.scapeRemoved(scapeEvent);
+ }
+
+ @Override
+ public void scapeSetup(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.CREATE, model);
+ }
+
+ @Override
+ public void scapeStarted(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.START, model);
+ }
+
+ @Override
+ public void scapeStopped(ScapeEvent scapeEvent) {
+ wrapped.stateChange(LifeCycleState.STOP, model);
+ }
+
+ @Override
+ public Scape getScape() {
+ return scape;
+ }
+
+ @Override
+ public boolean isGraphic() {
+ return false;
+ }
+
+ @Override
+ public boolean isLifeOfScape() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return wrapped.toString() + " Wrapped";
+ }
+
+ @Override
+ public Object clone() {
+ ModelWrapperScapeListener clone = (ModelWrapperScapeListener) super.clone();
+ return clone;
+ }
}
diff --git a/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ScapeWrapperModel.java b/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ScapeWrapperModel.java
index c17505a1..022d4aff 100644
--- a/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ScapeWrapperModel.java
+++ b/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ascape/src/org/eclipse/amp/escape/ascape/wrap/ScapeWrapperModel.java
@@ -24,262 +24,129 @@ import org.ascape.model.Scape;
import org.eclipse.amp.axf.core.IEngine;
import org.eclipse.amp.axf.core.ILifeCycleListener;
import org.eclipse.amp.axf.core.IModel;
-import org.eclipse.gef.EditPartFactory;
-import org.eclipse.jface.viewers.ILabelProviderListener;
-
-
-// TODO: Auto-generated Javadoc
-/**
- * The Class ScapeWrapperModel.
- */
public class ScapeWrapperModel implements IModel {
- Scape scape;
-
- IModel model;
-
- EditPartFactory factory;
-
- EditPartFactory treeFactory;
-
- Collection<ILifeCycleListener> listeners = new ArrayList<ILifeCycleListener>();
-
- Map<ILifeCycleListener, ModelWrapperScapeListener> wrapperForListener = new HashMap<ILifeCycleListener, ModelWrapperScapeListener>();
-
- boolean closed;
-
- /**
- * Instantiates a new scape wrapper model.
- *
- * @param scape the scape
- */
- public ScapeWrapperModel(Scape scape) {
- super();
- this.scape = scape;
- if (!scape.isRoot()) {
- model = new ScapeWrapperModel(scape.getRoot());
- } else {
- model = this;
- }
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IModel#getName()
- */
- public String getName() {
- return scape.getName();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IModel#getPeriod()
- */
- public int getPeriod() {
- return scape.getPeriod();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IModel#getEngine()
- */
- public IEngine getEngine() {
- return (IEngine) scape.getRunner();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IModel#getRoot()
- */
- public Object getRoot() {
- return getScape();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IModel#getStopPeriod()
- */
- public int getStopPeriod() {
- return scape.getStopPeriod();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IModel#getTimeDescription()
- */
- public String getTimeDescription() {
- return scape.getPeriodDescription();
- }
-
- /**
- * @param listener
- * @see org.eclipse.amp.axf.core.IObservationProvider#addModelListener(org.eclipse.amp.axf.core.ILifeCycleListener)
- */
- public void addModelListener(final ILifeCycleListener listener) {
- new Thread() {
- public void run() {
- listeners.add(listener);
- if (!(listener instanceof ScapeWrapperModelListener)) {
- ModelWrapperScapeListener wrapper = new ModelWrapperScapeListener(ScapeWrapperModel.this, scape,
- listener);
- scape.addView(wrapper);
- wrapperForListener.put(listener, wrapper);
- }
- };
- }.start();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#getModelListeners()
- */
- public Collection<ILifeCycleListener> getModelListeners() {
- return listeners;
- }
-
- /**
- * @param listener
- * @see org.eclipse.amp.axf.core.IObservationProvider#removeModelListener(org.eclipse.amp.axf.core.ILifeCycleListener)
- */
- public void removeModelListener(final ILifeCycleListener listener) {
- new Thread() {
- public void run() {
- listeners.remove(listener);
- if (listener instanceof ScapeWrapperModelListener) {
- scape.removeScapeListener(((ScapeWrapperModelListener) listener).getWrapped());
- }
- // ModelWrapperScapeListener wrapper = wrapperForListener.get(listener);
- // if (wrapper != null) {
- // scape.removeScapeListener(wrapper);
- // }
- listener.observationEnd(ScapeWrapperModel.this);
- }
- }.start();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#isInitialized()
- */
- public boolean isInitialized() {
- return scape.isInitialized();
- }
-
- /**
- * Gets the scape.
- *
- * @return the scape
- */
- public Scape getScape() {
- return scape;
- }
-
- /**
- * Gets the text.
- *
- * @param element the element
- *
- * @return the text
- */
- public String getText(Object element) {
- // TODO Auto-generated method stub
- return null;
- }
-
- /**
- * Adds the listener.
- *
- * @param listener the listener
- */
- public void addListener(ILabelProviderListener listener) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * Dispose.
- */
- public void dispose() {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * Checks if is label property.
- *
- * @param element the element
- * @param property the property
- *
- * @return true, if is label property
- */
- public boolean isLabelProperty(Object element, String property) {
- // TODO Auto-generated method stub
- return false;
- }
-
- /**
- * Removes the listener.
- *
- * @param listener the listener
- */
- public void removeListener(ILabelProviderListener listener) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#isActive()
- */
- public boolean isActive() {
- return getScape().isRunning();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#isCreated()
- */
- public boolean isCreated() {
- return getScape().isRunning();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#isEnded()
- */
- public boolean isEnded() {
- return closed;
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#isEnding()
- */
- public boolean isEnding() {
- return getScape().getRunner().isCloseRequested();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#isStarted()
- */
- public boolean isStarted() {
- return getScape().isInitialized() && getScape().isRunning();
- }
-
- /**
- * @return
- * @see org.eclipse.amp.axf.core.IObservationProvider#isStopped()
- */
- public boolean isStopped() {
- return !getScape().getRunner().isRunning() && !isEnded();
- }
-
- /**
- * @param closed the closed to set
- */
- public void setClosed(boolean closed) {
- this.closed = closed;
- }
+ Collection<ILifeCycleListener> listeners = new ArrayList<ILifeCycleListener>();
+
+ Map<ILifeCycleListener, ModelWrapperScapeListener> wrapperForListener = new HashMap<ILifeCycleListener, ModelWrapperScapeListener>();
+
+ private Scape scape;
+
+ private boolean closed;
+
+ /**
+ * Instantiates a new scape wrapper model.
+ *
+ * @param scape
+ * the scape
+ */
+ public ScapeWrapperModel(Scape scape) {
+ super();
+ this.scape = scape;
+ }
+
+ public String getName() {
+ return scape.getName();
+ }
+
+ public int getPeriod() {
+ return scape.getPeriod();
+ }
+
+ public IEngine getEngine() {
+ return (IEngine) scape.getRunner();
+ }
+
+ public Object getRoot() {
+ return getScape();
+ }
+
+ public int getStopPeriod() {
+ return scape.getStopPeriod();
+ }
+
+ public String getTimeDescription() {
+ return scape.getPeriodDescription();
+ }
+
+ public void addModelListener(final ILifeCycleListener listener) {
+ new Thread() {
+ @Override
+ public void run() {
+ listeners.add(listener);
+ if (!(listener instanceof ScapeWrapperModelListener)) {
+ ModelWrapperScapeListener wrapper = new ModelWrapperScapeListener(ScapeWrapperModel.this, getScape(), listener);
+ getScape().addView(wrapper);
+ wrapperForListener.put(listener, wrapper);
+ }
+ }
+ }.start();
+ }
+
+ public Collection<ILifeCycleListener> getModelListeners() {
+ return listeners;
+ }
+
+ public void removeModelListener(final ILifeCycleListener listener) {
+ new Thread() {
+ @Override
+ public void run() {
+ listeners.remove(listener);
+ if (listener instanceof ScapeWrapperModelListener) {
+ getScape().removeScapeListener(((ScapeWrapperModelListener) listener).getWrapped());
+ }
+ listener.observationEnd(ScapeWrapperModel.this);
+ }
+ }.start();
+ }
+
+ public boolean isInitialized() {
+ return scape.isInitialized();
+ }
+
+ /**
+ * Gets the scape.
+ *
+ * @return the scape
+ */
+ public Scape getScape() {
+ return scape;
+ }
+
+ public boolean isActive() {
+ return getScape().isRunning();
+ }
+
+ public boolean isCreated() {
+ return getScape().isRunning();
+ }
+
+ public boolean isEnded() {
+ return closed;
+ }
+
+ public boolean isEnding() {
+ return getScape().getRunner().isCloseRequested();
+ }
+
+ public boolean isRunning() {
+ return getScape().isInitialized() && getScape().isRunning();
+ }
+
+ public boolean isPaused() {
+ return getScape().isInitialized() && getScape().isPaused();
+ }
+
+ public boolean isStopped() {
+ return !getScape().getRunner().isRunning() && !isEnded();
+ }
+
+ /**
+ * @param closed
+ * the closed to set
+ */
+ public void setClosed(boolean closed) {
+ this.closed = closed;
+ }
}
diff --git a/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ide/src/org/eclipse/amp/escape/ide/EclipseEscapeRunner.java b/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ide/src/org/eclipse/amp/escape/ide/EclipseEscapeRunner.java
index 72eab187..c0fa3358 100644
--- a/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ide/src/org/eclipse/amp/escape/ide/EclipseEscapeRunner.java
+++ b/org.eclipse.amp.escape/plugins/org.eclipse.amp.escape.ide/src/org/eclipse/amp/escape/ide/EclipseEscapeRunner.java
@@ -269,7 +269,7 @@ public class EclipseEscapeRunner extends NonGraphicRunner implements IEngine {
}
try {
long elapsed = 0;
- while (isCloseRequested() && getModelThread() != null && getModelThread().isAlive() && elapsed <= KILL_AFTER_NO_RESPONSE_TIME) {
+ while (isCloseRequested() && isThreadAlive() && elapsed <= KILL_AFTER_NO_RESPONSE_TIME) {
if (elapsed >= KILL_AFTER_NO_RESPONSE_TIME) {
if (modelMonitor != null) {
modelMonitor.setTaskName("Forcing Close");
@@ -481,4 +481,9 @@ public class EclipseEscapeRunner extends NonGraphicRunner implements IEngine {
this.closeOnStop = closeOnStop;
}
+ @Override
+ public boolean isThreadAlive() {
+ return isModelThreadAlive();
+ }
+
}

Back to the top