/// <summary> /// Constructor /// </summary> /// <param name="simulations">The top level simulations object.</param> /// <param name="simulation">The simulation object clicked on.</param> /// <param name="presenter">The explorer presenter.</param> public RunCommand(Simulations simulations, Model simulation, ExplorerPresenter presenter) { this.simulations = simulations; this.modelClicked = simulation; this.explorerPresenter = presenter; jobManager = new JobManager(); jobManager.AllJobsCompleted += OnComplete; }
/// <summary> /// Initializes a new instance of the <see cref="VariableExpression" /> class. /// </summary> /// <param name="expression">The string expression</param> /// <param name="model">The model</param> public VariableExpression(string expression, Model model) { this.expression = expression; this.Object = model; // Perform initial parsing. this.fn = new ExpressionEvaluator(); this.fn.Parse(this.expression.Trim()); this.fn.Infix2Postfix(); }
/// <summary> /// Return a model with the specified name is in scope. Returns null if none found. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="relativeTo">The model calling this method</param> /// <returns>The found model or null if not found</returns> public Model Find(string namePath, Model relativeTo) { // Look in cache first. string cacheKey = "INSCOPENAME|" + namePath; object value = GetFromCache(cacheKey, relativeTo); if (value != null) { return (value as IVariable).Value as Model; } // Not in cache - get all in scope and return the one matching namePath. foreach (Model model in this.FindAll(relativeTo)) { if (model.Name.Equals(namePath, StringComparison.CurrentCultureIgnoreCase)) { AddToCache(cacheKey, relativeTo, new VariableObject(model)); return model; } } return null; }
/// <summary> /// Return a model with the specified type is in scope. Returns null if none found. /// </summary> /// <param name="type">The type of the object to return</param> /// <param name="relativeTo">The model calling this method</param> /// <returns>The found model or null if not found</returns> public Model Find(Type type, Model relativeTo) { // Look in cache first. string cacheKey = "INSCOPETYPE|" + type.Name; object value = GetFromCache(cacheKey, relativeTo); if (value != null) { return (value as IVariable).Value as Model; } // Not in cache - get all in scope and return the one matching namePath. foreach (Model model in this.FindAll(relativeTo)) { if (type.IsAssignableFrom(model.GetType())) { AddToCache(cacheKey, relativeTo, new VariableObject(model)); return model; } } return null; }
/// <summary> /// Apply commands. /// </summary> /// <param name="model">The underlying model to apply the commands to</param> public void Apply(Model model) { if (this.Commands != null) { foreach (string command in this.Commands) { string propertyName = command; string propertyValue = StringUtilities.SplitOffAfterDelimiter(ref propertyName, "="); propertyName = propertyName.TrimEnd(); propertyValue = propertyValue.TrimEnd(); if (propertyName != string.Empty && propertyValue != string.Empty) { IVariable property = Apsim.GetVariableObject(model, propertyName) as IVariable; if (property == null) throw new Exception("Cannot find cultivar property: " + propertyName); if (property.GetType() != null) { object oldValue = property.Value; if (oldValue is string || oldValue.GetType().IsArray || !oldValue.GetType().IsClass) { this.oldPropertyValues.Add(oldValue); property.Value = propertyValue; this.properties.Add(property); } else throw new ApsimXException(this, "Invalid type for setting cultivar parameter: " + propertyName + ". Must be a built-in type e.g. double"); } else { throw new ApsimXException(this, "While applying cultivar '" + Name + "', could not find property name '" + propertyName + "'"); } } } } }
/// <summary> /// Get an object from the cache. /// </summary> /// <param name="key">The cache key</param> /// <param name="relativeTo">The model the object is relative to</param> /// <returns>The object or null if not found.</returns> private object GetFromCache(string key, Model relativeTo) { if (cache.ContainsKey(relativeTo)) { object value = this.cache[relativeTo].GetValueForKey(key); if (value != null) { return value; } } return null; }
/// <summary> /// Add the specified object to the cache. /// </summary> /// <param name="key">cache key</param> /// <param name="relativeTo">Model for which the object is relative to</param> /// <param name="obj">The object to store.</param> private void AddToCache(string key, Model relativeTo, object obj) { if (obj != null) { CacheForModel cacheForModel = null; if (this.cache.ContainsKey(relativeTo)) cacheForModel = this.cache[relativeTo]; else { cacheForModel = new CacheForModel(); this.cache.Add(relativeTo, cacheForModel); } cacheForModel.cache.Add(key, obj); } }
/// <summary> /// Set the value of a variable. Will throw if variable doesn't exist. /// </summary> /// <param name="namePath">The name of the object to set</param> /// <param name="relativeTo">The model calling this method</param> /// <param name="value">The value to set the property to</param> public void Set(string namePath, Model relativeTo, object value) { IVariable variable = this.GetInternal(namePath, relativeTo); if (variable == null) { throw new ApsimXException(relativeTo, "Cannot set the value of variable '" + namePath + "'. Variable doesn't exist"); } else { variable.Value = value; } }
/// <summary> /// Generate xml for the new object and import the serialised xml into the new document /// </summary> /// <param name="destParent">Destination parent node that the new child is added to</param> /// <param name="newNode">The new node</param> /// <param name="newObject">The object to import into the document</param> /// <param name="objName">Name to set the new object</param> /// <returns>The new created node</returns> private static XmlNode ImportObject(XmlNode destParent, XmlNode newNode, Model newObject, string objName) { newObject.Name = objName; string newObjxml = XmlUtilities.Serialise(newObject, false); XmlDocument xdoc = new XmlDocument(); xdoc.LoadXml(newObjxml); newNode = destParent.OwnerDocument.ImportNode(xdoc.DocumentElement, true); newNode = destParent.AppendChild(newNode); return newNode; }
/// <summary> /// Adds an event subscriber to this event. /// </summary> /// <param name="model">The model instance of the subscriber</param> /// <param name="eventDelegate">The delegate of the event subscriber</param> public void AddEventHandler(Model model, Delegate eventDelegate) { EventInfo.AddEventHandler(model, eventDelegate); }
/// <summary> /// Attach the model to the view. /// </summary> /// <param name="model">The underlying model we are to use</param> /// <param name="view">The underlying view we are to attach to</param> /// <param name="explorerPresenter">Our parent explorerPresenter</param> public void Attach(object model, object view, ExplorerPresenter explorerPresenter) { this.model = model as Model; this.view = view as IProfileView; this.explorerPresenter = explorerPresenter; // Setup the property presenter and view. Hide the view if there are no properties to show. this.propertyPresenter = new PropertyPresenter(); this.propertyPresenter.Attach(this.model, this.view.PropertyGrid, this.explorerPresenter); // Create a list of profile (array) properties. Create a table from them and // hand the table to the profile grid. this.FindAllProperties(this.model); // Populate the grid this.PopulateGrid(); // Populate the graph. this.graph = Utility.Graph.CreateGraphFromResource(model.GetType().Name + "Graph"); if (this.graph == null) { this.view.ShowGraph(false); } else { parentForGraph = this.model.Parent as IModel; if (this.parentForGraph != null) { this.parentForGraph.Children.Add(this.graph); this.graph.Parent = this.parentForGraph; this.view.ShowGraph(true); int padding = (this.view as ProfileView).MainWidget.Allocation.Width / 2 / 2; this.view.Graph.LeftRightPadding = padding; this.graphPresenter = new GraphPresenter(); this.graphPresenter.Attach(this.graph, this.view.Graph, this.explorerPresenter); } } // Trap the invoking of the ProfileGrid 'CellValueChanged' event so that // we can save the contents. this.view.ProfileGrid.CellsChanged += this.OnProfileGridCellValueChanged; // Trap the right click on column header so that we can potentially put // units on the context menu. this.view.ProfileGrid.ColumnHeaderClicked += this.OnColumnHeaderClicked; // Trap the model changed event so that we can handle undo. this.explorerPresenter.CommandHistory.ModelChanged += this.OnModelChanged; this.view.ProfileGrid.ResizeControls(); this.view.PropertyGrid.ResizeControls(); }
/// <summary> /// Setup the variables grid based on the properties in the model. /// </summary> /// <param name="model">The underlying model we are to use to find the properties</param> private void FindAllProperties(Model model) { // Properties must be public with a getter and a setter. They must also // be either double[] or string[] type. foreach (PropertyInfo property in model.GetType().GetProperties()) { bool hasDescription = property.IsDefined(typeof(DescriptionAttribute), false); if (hasDescription && property.CanRead) { if (property.PropertyType == typeof(double[]) || property.PropertyType == typeof(string[])) { this.propertiesInGrid.Add(new VariableProperty(model, property)); } } } }
/// <summary>Runs the specified simulations.</summary> /// <param name="model">Simulations to run.</param> /// <param name="simulations">Simulations model.</param> /// <param name="runTests">Run the test nodes?</param> /// <returns>A runnable job or null if nothing to run.</returns> public static JobManager.IRunnable ForSimulations(Simulations simulations, Model model, bool runTests) { return new RunOrganiser(simulations, model, runTests); }
/// <summary>Roots the simulations.</summary> /// <param name="model">The model.</param> /// <returns></returns> private static Simulations RootSimulations(Model model) { Model m = model; while (m != null && m.Parent != null && !(m is Simulations)) m = m.Parent as Model; return m as Simulations; }
/// <summary>Find all simulations under the specified parent model.</summary> /// <param name="parent">The parent.</param> /// <returns></returns> public static Simulation[] FindAllSimulationsToRun(Model parent) { List<Simulation> simulations = new List<Simulation>(); if (parent is Experiment) simulations.AddRange((parent as Experiment).Create()); else if (parent is Simulation) { Simulation clonedSim = Apsim.Clone(parent) as Simulation; CallOnLoaded(clonedSim); simulations.Add(clonedSim); } else { // Look for simulations. foreach (Model model in Apsim.ChildrenRecursively(parent)) { if (model is Experiment) simulations.AddRange((model as Experiment).Create()); else if (model is Simulation && !(model.Parent is Experiment)) { Simulation clonedSim = Apsim.Clone(model) as Simulation; CallOnLoaded(clonedSim); simulations.Add(clonedSim); } } } // Make sure each simulation has it's filename set correctly. foreach (Simulation simulation in simulations) { if (simulation.FileName == null) simulation.FileName = RootSimulations(parent).FileName; } return simulations.ToArray(); }
/// <summary>Sets the not visible.</summary> /// <param name="ModelFromResource">The model from resource.</param> private static void SetNotVisible(Model ModelFromResource) { foreach (Model child in ModelFromResource.Children) { child.IsHidden = true; SetNotVisible(child); } }
/// <summary> /// Constructor. /// </summary> public MoveModelCommand(Model FromModel, Model ToParent) { this.FromModel = FromModel; this.ToParent = ToParent; }
/// <summary> /// Initializes a new instance of the <see cref="RenameModelCommand"/> class. /// </summary> /// <param name="modelToRename">The model to rename.</param> /// <param name="newName">The new name.</param> /// <param name="explorerView">The explorer view.</param> public RenameModelCommand(Model modelToRename, string newName, Interfaces.IExplorerView explorerView) { this.modelToRename = modelToRename; this.newName = newName; this.explorerView = explorerView; }
/// <summary> /// Return all models within scope of the specified relative model. /// </summary> /// <param name="relativeTo">The model calling this method</param> /// <returns>The found models or an empty array if not found.</returns> public Model[] FindAll(Model relativeTo) { // Look in cache first. string cacheKey = "ALLINSCOPE"; object value = GetFromCache(cacheKey, relativeTo); if (value != null) { return value as Model[]; } // Get all children first. List<Model> modelsInScope = new List<Model>(); foreach (Model child in Apsim.ChildrenRecursively(relativeTo)) modelsInScope.Add(child); // Add relativeTo. //modelsInScope.Add(relativeTo); // Get siblings and parents siblings and parents, parents siblings etc // until we reach a Simulations or Simulation model. if (!(relativeTo is Simulations)) { Model relativeToParent = relativeTo; do { foreach (IModel model in Apsim.Siblings(relativeToParent)) modelsInScope.Add(model as Model); relativeToParent = relativeToParent.Parent as Model; // Add in the top level model that we stopped on. if (relativeToParent != null) { modelsInScope.Add(relativeToParent); } } while (relativeToParent != null && !(relativeToParent is Simulation) && !(relativeToParent is Simulations)); } // Add the in scope models to the cache and return them AddToCache(cacheKey, relativeTo, modelsInScope.ToArray()); return modelsInScope.ToArray(); }
/// <summary> /// Return all models of the specified type within scope of the specified relative model. /// </summary> /// <param name="type">The type of the models to return</param> /// <param name="relativeTo">The model calling this method</param> /// <returns>The found models or an empty array if not found.</returns> public Model[] FindAll(Type type, Model relativeTo) { // Look in cache first. string cacheKey = "ALLINSCOPEOFTYPE|" + type.Name; object value = GetFromCache(cacheKey, relativeTo); if (value != null) { return value as Model[]; } List<Model> modelsToReturn = new List<Model>(); foreach (Model model in this.FindAll(relativeTo)) { if (type.IsAssignableFrom(model.GetType())) { modelsToReturn.Add(model); } else { if (model is Manager) { Manager manager = model as Manager; if (manager.Script != null && type.IsAssignableFrom(manager.Script.GetType())) { if (manager.Script != relativeTo) modelsToReturn.Add(manager.Script); } } } } AddToCache(cacheKey, relativeTo, modelsToReturn.ToArray()); return modelsToReturn.ToArray(); }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="relativeTo">The model calling this method</param> /// <param name="ignoreCase">If true, ignore case when searching for the object or property</param> /// <returns>The found object or null if not found</returns> public object Get(string namePath, Model relativeTo, bool ignoreCase = false) { IVariable variable = this.GetInternal(namePath, relativeTo, ignoreCase); if (variable == null) { return variable; } else { return variable.Value; } }
/// <summary> /// Setup the profile grid based on the properties in the model. /// </summary> /// <param name="model">The underlying model we are to use to find the properties</param> private void FindAllProperties(Model model) { // Properties must be public with a getter and a setter. They must also // be either double[] or string[] type. foreach (PropertyInfo property in model.GetType().GetProperties()) { bool hasDescription = property.IsDefined(typeof(DescriptionAttribute), false); if (hasDescription && property.CanRead) { if (this.model.Name == "Water" && property.Name == "Depth" && typeof(ISoilCrop).IsAssignableFrom(model.GetType())) { } else if (property.PropertyType == typeof(double[]) || property.PropertyType == typeof(string[])) { this.propertiesInGrid.Add(new VariableProperty(model, property)); } else if (property.PropertyType.FullName.Contains("SoilCrop")) { List<ISoilCrop> crops = property.GetValue(model, null) as List<ISoilCrop>; if (crops != null) { foreach (ISoilCrop crop in crops) { this.FindAllProperties(crop as Model); } } } } } }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="relativeTo">The model calling this method</param> /// <param name="ignoreCase">If true, ignore case when searching for the object or property</param> /// <returns>The found object or null if not found</returns> public IVariable GetInternal(string namePath, Model relativeTo, bool ignoreCase = false) { Model relativeToModel = relativeTo; string cacheKey = namePath; StringComparison compareType = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; // Look in cache first. object value = GetFromCache(cacheKey, relativeToModel); if (value != null) { return value as IVariable; } IVariable returnVariable = null; if (namePath == null || namePath.Length == 0) { return null; } else if (namePath[0] != '.' && namePath[0] != '.' && namePath.IndexOfAny("(+*/".ToCharArray()) != -1) { // expression - need a better way of detecting an expression returnVariable = new VariableExpression(namePath, relativeToModel); } else { // Remove a square bracketed model name and change our relativeTo model to // the referenced model. if (namePath.StartsWith("[")) { int posCloseBracket = namePath.IndexOf(']'); if (posCloseBracket == -1) { return null; } string modelName = namePath.Substring(1, posCloseBracket - 1); namePath = namePath.Remove(0, posCloseBracket + 1); Model foundModel = this.Find(modelName, relativeToModel); if (foundModel == null) { // Didn't find a model with a name matching the square bracketed string so // now try and look for a model with a type matching the square bracketed string. Type[] modelTypes = GetTypeWithoutNameSpace(modelName); if (modelTypes.Length == 1) foundModel = this.Find(modelTypes[0], relativeToModel); } if (foundModel == null) return null; else relativeToModel = foundModel; } else if (namePath.StartsWith(".")) { // Absolute path Model root = relativeToModel; while (root.Parent != null) { root = root.Parent as Model; } relativeToModel = root; int posPeriod = namePath.IndexOf('.', 1); if (posPeriod == -1) { posPeriod = namePath.Length; } namePath = namePath.Remove(0, posPeriod); if (namePath.StartsWith(".")) { namePath.Remove(1); } } // Now walk the series of '.' separated path bits, assuming the path bits // are child models. Stop when we can't find the child model. string[] namePathBits = namePath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int i; for (i = 0; i < namePathBits.Length; i++) { IModel localModel = relativeToModel.Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType)); if (localModel == null) { break; } else { relativeToModel = localModel as Model; } } // At this point there are only 2 possibilities. We have encountered a // PropertyInfo or the path is invalid. // We now need to loop through the remaining path bits and keep track of each // section of the path as each section will have to be evaulated everytime a // a get is done for this path. // The variable 'i' will point to the name path that cannot be found as a model. object relativeToObject = relativeToModel; List<IVariable> properties = new List<IVariable>(); properties.Add(new VariableObject(relativeToModel)); for (int j = i; j < namePathBits.Length; j++) { // look for an array specifier e.g. sw[2] string arraySpecifier = null; if (namePathBits[j].Contains("[")) { arraySpecifier = StringUtilities.SplitOffBracketedValue(ref namePathBits[j], '[', ']'); } // Look for either a property or a child model. IModel localModel = null; if (relativeToObject == null) return null; PropertyInfo propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j]); if (propertyInfo == null && ignoreCase) // If not found, try using a case-insensitive search propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); if (propertyInfo == null && relativeToObject is Model) { // Not a property, may be a child model. localModel = (relativeToObject as IModel).Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType)); if (localModel == null) { return null; } properties.Add(new VariableObject(localModel)); relativeToObject = localModel; } else if (propertyInfo != null) { VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(property); relativeToObject = property.Value; } else if (relativeToObject is IList) { // Special case: we are trying to get a property of an array(IList). In this case // we want to return the property value for all items in the array. VariableProperty property = new VariableProperty(relativeToObject, namePathBits[j]); properties.Add(property); relativeToObject = property.Value; } else { return null; } } // We now have a list of IVariable instances that can be evaluated to // produce a return value for the given path. Wrap the list into an IVariable. returnVariable = new VariableComposite(namePath, properties); } // Add variable to cache. AddToCache(cacheKey, relativeTo, returnVariable); return returnVariable; }
/// <summary> /// Return a list of models that are visible for event connecting purposes. /// </summary> /// <param name="relativeTo">The model to use as a base for looking for all other models in scope</param> /// <returns>The list of visible models for event connection</returns> private static List<IModel> GetModelsVisibleToEvents(Model relativeTo) { // This is different to models in scope unfortunately. Need to rethink this. List<IModel> models = new List<IModel>(); // Find our parent Simulation or Zone. Model obj = relativeTo; while (obj != null && !(obj is Zone) && !(obj is Simulation)) { obj = obj.Parent as Model; } if (obj == null) throw new ApsimXException(relativeTo, "Cannot find models to connect events to"); if (obj is Simulation) { models.AddRange(Apsim.ChildrenRecursively(obj)); } else { // return all models in zone and all direct children of zones parent. models.AddRange(Apsim.ChildrenRecursively(obj)); if (obj.Parent != null) models.AddRange(obj.Parent.Children); } return models; }
/// <summary> /// Generate xml for the new object and import the serialised xml into the new document /// </summary> /// <param name="destParent">Destination parent node that the new child is added to</param> /// <param name="newNode">The new node</param> /// <param name="newObject">The object to import into the document</param> /// <param name="objName">Name to set the new object</param> /// <returns>The new created node</returns> private static XmlNode ImportObject(XmlNode destParent, XmlNode newNode, Model newObject, string objName) { // Try using the pre built serialization assembly first. string binDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location); string deserializerFileName = Path.Combine(binDirectory, "Models.XmlSerializers.dll"); newObject.Name = objName; string newObjxml = XmlUtilities.Serialise(newObject, false, deserializerFileName); XmlDocument xdoc = new XmlDocument(); xdoc.LoadXml(newObjxml); newNode = destParent.OwnerDocument.ImportNode(xdoc.DocumentElement, true); newNode = destParent.AppendChild(newNode); return newNode; }