/// <summary>Get a list of all actual series to put on the graph.</summary> /// <param name="storage">Storage service (required for access to checkpoint names).</param> /// <param name="definitions">Series definitions to be used (allows for caching of data).</param> /// <param name="simulationsFilter">Unused simulation names filter.</param> public IEnumerable <SeriesDefinition> GetSeriesToPutOnGraph(IStorageReader storage, IEnumerable <SeriesDefinition> definitions, List <string> simulationsFilter = null) { stats.Clear(); equationColours.Clear(); int checkpointNumber = 0; List <SeriesDefinition> regressionLines = new List <SeriesDefinition>(); foreach (var checkpointName in storage.CheckpointNames) { // Get all x/y data List <double> x = new List <double>(); List <double> y = new List <double>(); foreach (SeriesDefinition definition in definitions) { if (definition.CheckpointName == checkpointName) { if (definition.X != null && definition.Y != null) { if (ReflectionUtilities.IsNumericType(definition.X.GetType().GetElementType()) && ReflectionUtilities.IsNumericType(definition.Y.GetType().GetElementType())) { x.AddRange(definition.X.Cast <object>().Select(xi => Convert.ToDouble(xi, CultureInfo.InvariantCulture)).ToArray()); y.AddRange(definition.Y.Cast <object>().Select(yi => Convert.ToDouble(yi, CultureInfo.InvariantCulture)).ToArray()); } } } } if (ForEachSeries) { // Display a regression line for each series. // todo - should this also filter on checkpoint name? int numDefinitions = definitions.Count(); foreach (SeriesDefinition definition in definitions) { if (definition.X is double[] && definition.Y is double[]) { SeriesDefinition regressionSeries = PutRegressionLineOnGraph(definition.X, definition.Y, definition.Colour, null); if (regressionSeries != null) { regressionLines.Add(regressionSeries); equationColours.Add(definition.Colour); } } } } else { var regresionLineName = "Regression line"; if (checkpointName != "Current") { regresionLineName = "Regression line (" + checkpointName + ")"; } // Display a single regression line for all data. if (x.Count > 0 && y.Count == x.Count) { SeriesDefinition regressionSeries = PutRegressionLineOnGraph(x, y, ColourUtilities.ChooseColour(checkpointNumber), regresionLineName); if (regressionSeries != null) { regressionLines.Add(regressionSeries); equationColours.Add(ColourUtilities.ChooseColour(checkpointNumber)); } } } if (showOneToOne) { regressionLines.Add(Put1To1LineOnGraph(x, y)); } checkpointNumber++; } return(regressionLines); }
/// <summary> /// Constructor /// </summary> public MainView(ViewBase owner = null) : base(owner) { MasterView = this; numberOfButtons = 0; Builder builder = BuilderFromResource("ApsimNG.Resources.Glade.MainView.glade"); window1 = (Window)builder.GetObject("window1"); progressBar = (ProgressBar)builder.GetObject("progressBar"); statusWindow = (TextView)builder.GetObject("StatusWindow"); stopButton = (Button)builder.GetObject("stopButton"); notebook1 = (Notebook)builder.GetObject("notebook1"); notebook2 = (Notebook)builder.GetObject("notebook2"); vbox1 = (VBox)builder.GetObject("vbox1"); vbox2 = (VBox)builder.GetObject("vbox2"); hpaned1 = (HPaned)builder.GetObject("hpaned1"); hbox1 = (HBox)builder.GetObject("hbox1"); mainWidget = window1; window1.Icon = new Gdk.Pixbuf(null, "ApsimNG.Resources.apsim logo32.png"); listButtonView1 = new ListButtonView(this); listButtonView1.ButtonsAreToolbar = true; vbox1.PackEnd(listButtonView1.MainWidget, true, true, 0); listButtonView2 = new ListButtonView(this); listButtonView2.ButtonsAreToolbar = true; vbox2.PackEnd(listButtonView2.MainWidget, true, true, 0); hpaned1.PositionSet = true; hpaned1.Child2.Hide(); hpaned1.Child2.NoShowAll = true; notebook1.SetMenuLabel(vbox1, LabelWithIcon(indexTabText, "go-home")); notebook2.SetMenuLabel(vbox2, LabelWithIcon(indexTabText, "go-home")); notebook1.SwitchPage += OnChangeTab; notebook2.SwitchPage += OnChangeTab; notebook1.GetTabLabel(notebook1.Children[0]).Name = "selected-tab"; hbox1.HeightRequest = 20; TextTag tag = new TextTag("error"); // Make errors orange-ish in dark mode. if (Utility.Configuration.Settings.DarkTheme) { tag.ForegroundGdk = Utility.Colour.ToGdk(ColourUtilities.ChooseColour(1)); } else { tag.Foreground = "red"; } statusWindow.Buffer.TagTable.Add(tag); tag = new TextTag("warning"); // Make warnings yellow in dark mode. if (Utility.Configuration.Settings.DarkTheme) { tag.ForegroundGdk = Utility.Colour.ToGdk(ColourUtilities.ChooseColour(7)); } else { tag.Foreground = "brown"; } statusWindow.Buffer.TagTable.Add(tag); tag = new TextTag("normal"); tag.Foreground = "blue"; statusWindow.Visible = false; stopButton.Image = new Gtk.Image(new Gdk.Pixbuf(null, "ApsimNG.Resources.MenuImages.Delete.png", 12, 12)); stopButton.ImagePosition = PositionType.Right; stopButton.Image.Visible = true; stopButton.Clicked += OnStopClicked; window1.DeleteEvent += OnClosing; if (ProcessUtilities.CurrentOS.IsWindows && Utility.Configuration.Settings.Font == null) { // Default font on Windows is Segoe UI. Will fallback to sans if unavailable. Utility.Configuration.Settings.Font = Pango.FontDescription.FromString("Segoe UI 11"); } // Can't set font until widgets are initialised. if (Utility.Configuration.Settings.Font != null) { ChangeFont(Utility.Configuration.Settings.Font); } //window1.ShowAll(); if (ProcessUtilities.CurrentOS.IsMac) { InitMac(); //Utility.Configuration.Settings.DarkTheme = Utility.MacUtilities.DarkThemeEnabled(); } if (!ProcessUtilities.CurrentOS.IsLinux) { RefreshTheme(); } }
/// <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; this.view.ShowView(false); // 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 { this.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(); for (int col = 0; col < this.propertiesInGrid.Count; col++) { VariableProperty property = this.propertiesInGrid[col]; string columnName = property.Description; // crop colours if (property.CropName != null && columnName.Contains("LL")) { Series cropLLSeries = new Series(); cropLLSeries.Name = columnName; cropLLSeries.Colour = ColourUtilities.ChooseColour(this.graph.Children.Count); cropLLSeries.Line = LineType.Solid; cropLLSeries.Marker = MarkerType.None; cropLLSeries.Type = SeriesType.Scatter; cropLLSeries.ShowInLegend = true; cropLLSeries.XAxis = Axis.AxisType.Top; cropLLSeries.YAxis = Axis.AxisType.Left; cropLLSeries.YFieldName = "[Soil].DepthMidPoints"; cropLLSeries.XFieldName = "[" + (property.Object as Model).Name + "]." + property.Name; cropLLSeries.Parent = this.graph; this.graph.Children.Add(cropLLSeries); } } 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(); this.view.ShowView(true); }
/// <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; profileGrid.Attach(model, this.view.ProfileGrid, explorerPresenter); this.explorerPresenter = explorerPresenter; this.view.ShowView(false); // 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); propertyPresenter.ScalarsOnly = true; // Populate the grid this.PopulateGrid(); // Populate the graph. this.graph = Utility.Graph.CreateGraphFromResource("WaterGraph"); graph.Name = ""; if (this.graph == null) { this.view.ShowGraph(false); } else { // The graph's series contain many variables such as [Soil].LL. We now replace // these relative paths with absolute paths. foreach (Series series in Apsim.Children(graph, typeof(Series))) { series.XFieldName = series.XFieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); series.X2FieldName = series.X2FieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); series.YFieldName = series.YFieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); series.Y2FieldName = series.Y2FieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); } this.parentForGraph = this.model.Parent as IModel; if (this.parentForGraph != null) { // Don't add the graph as a child of the soil. This causes problems // (see bug #4622), and adding the soil as a parent is sufficient. 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(); for (int i = 0; i < this.profileGrid.Properties.Length; i++) { string columnName = profileGrid.Properties[i].Name; if (columnName.Contains("\r\n")) { StringUtilities.SplitOffAfterDelimiter(ref columnName, "\r\n"); } // crop colours if (columnName.Contains("LL")) { if (profileGrid.Properties[i].Object is SoilCrop) { string soilCropName = (profileGrid.Properties[i].Object as SoilCrop).Name; string cropName = soilCropName.Replace("Soil", ""); columnName = cropName + " " + columnName; } Series cropLLSeries = new Series(); cropLLSeries.Name = columnName; cropLLSeries.Colour = ColourUtilities.ChooseColour(this.graph.Children.Count); cropLLSeries.Line = LineType.Solid; cropLLSeries.Marker = MarkerType.None; cropLLSeries.Type = SeriesType.Scatter; cropLLSeries.ShowInLegend = true; cropLLSeries.XAxis = Axis.AxisType.Top; cropLLSeries.YAxis = Axis.AxisType.Left; cropLLSeries.YFieldName = (parentForGraph is Soil ? Apsim.FullPath(parentForGraph) : "[Soil]") + ".DepthMidPoints"; cropLLSeries.XFieldName = Apsim.FullPath((profileGrid.Properties[i].Object as IModel)) + "." + profileGrid.Properties[i].Name; //cropLLSeries.XFieldName = Apsim.FullPath(property.Object as Model) + "." + property.Name; cropLLSeries.Parent = this.graph; this.graph.Children.Add(cropLLSeries); } } this.graph.LegendPosition = Graph.LegendPositionType.RightTop; explorerPresenter.ApsimXFile.Links.Resolve(graphPresenter); this.graphPresenter.Attach(this.graph, this.view.Graph, this.explorerPresenter); graphPresenter.LegendInsideGraph = false; } } // Trap the model changed event so that we can handle undo. this.explorerPresenter.CommandHistory.ModelChanged += this.OnModelChanged; this.view.ShowView(true); }
/// <summary> /// Constructor /// </summary> public MainView(ViewBase owner = null) : base(owner) { MasterView = this; numberOfButtons = 0; Builder builder = BuilderFromResource("ApsimNG.Resources.Glade.MainView.glade"); window1 = (Window)builder.GetObject("window1"); progressBar = (ProgressBar)builder.GetObject("progressBar"); lblStatus = (Label)builder.GetObject("lblStatus"); statusWindow = (TextView)builder.GetObject("StatusWindow"); stopButton = (Button)builder.GetObject("stopButton"); notebook1 = (Notebook)builder.GetObject("notebook1"); notebook2 = (Notebook)builder.GetObject("notebook2"); vbox1 = (VBox)builder.GetObject("vbox1"); vbox2 = (VBox)builder.GetObject("vbox2"); hpaned1 = (HPaned)builder.GetObject("hpaned1"); hbox1 = (Widget)builder.GetObject("vbox3"); mainWidget = window1; window1.Icon = new Gdk.Pixbuf(null, "ApsimNG.Resources.apsim logo32.png"); listButtonView1 = new ListButtonView(this); listButtonView1.ButtonsAreToolbar = true; vbox1.PackEnd(listButtonView1.MainWidget, true, true, 0); listButtonView2 = new ListButtonView(this); listButtonView2.ButtonsAreToolbar = true; vbox2.PackEnd(listButtonView2.MainWidget, true, true, 0); hpaned1.PositionSet = true; hpaned1.Child2.Hide(); hpaned1.Child2.NoShowAll = true; notebook1.SetMenuLabel(vbox1, LabelWithIcon(indexTabText, "go-home")); notebook2.SetMenuLabel(vbox2, LabelWithIcon(indexTabText, "go-home")); notebook1.SwitchPage += OnChangeTab; notebook2.SwitchPage += OnChangeTab; notebook1.GetTabLabel(notebook1.Children[0]).Name = "selected-tab"; hbox1.HeightRequest = 20; // Normally, one would specify the style class in the UI (.glade) file. // However, doing so breaks gtk2-compatibility, so for now, we will just // set the style class in code. progressBar.StyleContext.AddClass("fat-progress-bar"); TextTag tag = new TextTag("error"); // Make errors orange-ish in dark mode. if (Utility.Configuration.Settings.DarkTheme) { tag.ForegroundGdk = Utility.Colour.ToGdk(ColourUtilities.ChooseColour(1)); } else { tag.Foreground = "red"; } statusWindow.Buffer.TagTable.Add(tag); tag = new TextTag("warning"); // Make warnings yellow in dark mode. if (Utility.Configuration.Settings.DarkTheme) { tag.ForegroundGdk = Utility.Colour.ToGdk(ColourUtilities.ChooseColour(7)); } else { tag.Foreground = "brown"; } statusWindow.Buffer.TagTable.Add(tag); tag = new TextTag("normal"); tag.Foreground = "blue"; statusWindow.Visible = false; stopButton.Image = new Gtk.Image(new Gdk.Pixbuf(null, "ApsimNG.Resources.MenuImages.Delete.png", 12, 12)); stopButton.ImagePosition = PositionType.Right; stopButton.Image.Visible = true; stopButton.Clicked += OnStopClicked; window1.DeleteEvent += OnClosing; // If font is null, or font family is null, or font size is 0, fallback // to the default font (on windows only). Pango.FontDescription f = null; if (!string.IsNullOrEmpty(Utility.Configuration.Settings.FontName)) { f = Pango.FontDescription.FromString(Utility.Configuration.Settings.FontName); } if (ProcessUtilities.CurrentOS.IsWindows && (string.IsNullOrEmpty(Utility.Configuration.Settings.FontName) || f.Family == null || f.Size == 0)) { // Default font on Windows is Segoe UI. Will fallback to sans if unavailable. Utility.Configuration.Settings.FontName = Pango.FontDescription.FromString("Segoe UI 11").ToString(); } // Can't set font until widgets are initialised. if (!string.IsNullOrEmpty(Utility.Configuration.Settings.FontName)) { try { Pango.FontDescription font = Pango.FontDescription.FromString(Utility.Configuration.Settings.FontName); ChangeFont(font); } catch (Exception err) { ShowError(err); } } //window1.ShowAll(); if (ProcessUtilities.CurrentOS.IsMac) { InitMac(); //Utility.Configuration.Settings.DarkTheme = Utility.MacUtilities.DarkThemeEnabled(); } if (!ProcessUtilities.CurrentOS.IsLinux) { RefreshTheme(); } LoadStylesheets(); }
/// <summary>Get a list of all actual series to put on the graph.</summary> /// <param name="storage">Storage service (required for access to checkpoint names).</param> /// <param name="definitions">Series definitions to be used (allows for caching of data).</param> /// <param name="simulationsFilter">Unused simulation names filter.</param> public IEnumerable <SeriesDefinition> GetSeriesToPutOnGraph(IStorageReader storage, IEnumerable <SeriesDefinition> definitions, List <string> simulationsFilter = null) { stats.Clear(); equationColours.Clear(); int checkpointNumber = 0; List <SeriesDefinition> regressionLines = new List <SeriesDefinition>(); foreach (var checkpointName in storage.CheckpointNames) { if (checkpointName != "Current" && !storage.GetCheckpointShowOnGraphs(checkpointName)) // smh // If "Show on graphs" is disabled on this checkpoint, skip it. { continue; } // Get all x/y data List <double> x = new List <double>(); List <double> y = new List <double>(); foreach (SeriesDefinition definition in definitions) { if (definition.CheckpointName == checkpointName) { if (definition.X != null && definition.Y != null) { if (ReflectionUtilities.IsNumericType(definition.X.GetType().GetElementType()) && ReflectionUtilities.IsNumericType(definition.Y.GetType().GetElementType())) { x.AddRange(definition.X.Cast <object>().Select(xi => Convert.ToDouble(xi, CultureInfo.InvariantCulture)).ToArray()); y.AddRange(definition.Y.Cast <object>().Select(yi => Convert.ToDouble(yi, CultureInfo.InvariantCulture)).ToArray()); } } } } try { if (ForEachSeries) { // Display a regression line for each series. // todo - should this also filter on checkpoint name? foreach (SeriesDefinition definition in definitions) { if (definition.X is double[] && definition.Y is double[]) { SeriesDefinition regressionSeries = PutRegressionLineOnGraph(definition.X, definition.Y, definition.Colour, null); if (regressionSeries != null) { regressionLines.Add(regressionSeries); equationColours.Add(definition.Colour); } } } } else { var regresionLineName = "Regression line"; if (checkpointName != "Current") { regresionLineName = "Regression line (" + checkpointName + ")"; } // Display a single regression line for all data. if (x.Count > 0 && y.Count == x.Count) { SeriesDefinition regressionSeries = PutRegressionLineOnGraph(x, y, ColourUtilities.ChooseColour(checkpointNumber), regresionLineName); if (regressionSeries != null) { regressionLines.Add(regressionSeries); equationColours.Add(ColourUtilities.ChooseColour(checkpointNumber)); } } } if (showOneToOne) { if (x.Count > 0 && y.Count == x.Count) { regressionLines.Add(Put1To1LineOnGraph(x, y)); } } } catch (Exception err) { IEnumerable <string> xs = definitions.Select(d => d.XFieldName).Distinct(); IEnumerable <string> ys = definitions.Select(d => d.YFieldName).Distinct(); string xFields = string.Join(", ", xs); string yFields = string.Join(", ", ys); throw new InvalidOperationException($"Unable to create regression line for checkpoint {checkpointName}. (x variables = [{xFields}], y variables = [{yFields}])", err); } checkpointNumber++; } return(regressionLines); }
/// <summary>Get a list of all actual series to put on the graph.</summary> /// <param name="storage">Storage service (required for access to checkpoint names).</param> /// <param name="definitions">Series definitions to be used (allows for caching of data).</param> /// <param name="simulationsFilter">Unused simulation names filter.</param> public IEnumerable <SeriesDefinition> GetSeriesToPutOnGraph(IStorageReader storage, IEnumerable <SeriesDefinition> definitions, List <string> simulationsFilter = null) { stats.Clear(); equationColours.Clear(); int checkpointNumber = 0; List <SeriesDefinition> regressionLines = new List <SeriesDefinition>(); foreach (var checkpointName in storage.CheckpointNames) { // Get all x/y data List <double> x = new List <double>(); List <double> y = new List <double>(); foreach (SeriesDefinition definition in definitions) { if (definition.CheckpointName == checkpointName) { if (definition.X is double[] && definition.Y is double[]) { x.AddRange(definition.X as IEnumerable <double>); y.AddRange(definition.Y as IEnumerable <double>); } } } if (ForEachSeries) { // Display a regression line for each series. // todo - should this also filter on checkpoint name? int numDefinitions = definitions.Count(); foreach (SeriesDefinition definition in definitions) { if (definition.X is double[] && definition.Y is double[]) { SeriesDefinition regressionSeries = PutRegressionLineOnGraph(definition.X, definition.Y, definition.Colour, null); if (regressionSeries != null) { regressionLines.Add(regressionSeries); equationColours.Add(definition.Colour); } } } } else { var regresionLineName = "Regression line"; if (checkpointName != "Current") { regresionLineName = "Regression line (" + checkpointName + ")"; } // Display a single regression line for all data. SeriesDefinition regressionSeries = PutRegressionLineOnGraph(x, y, ColourUtilities.ChooseColour(checkpointNumber), regresionLineName); if (regressionSeries != null) { regressionLines.Add(regressionSeries); equationColours.Add(ColourUtilities.ChooseColour(checkpointNumber)); } } if (showOneToOne) { regressionLines.Add(Put1To1LineOnGraph(x, y)); } checkpointNumber++; } return(regressionLines); }
/// <summary>Calculate / create a directed graph from model</summary> public void CalculateDirectedGraph() { DirectedGraph oldGraph = directedGraphInfo; if (directedGraphInfo == null) { directedGraphInfo = new DirectedGraph(); } directedGraphInfo.Begin(); bool needAtmosphereNode = false; foreach (NutrientPool pool in this.FindAllChildren <NutrientPool>()) { Point location = default(Point); Node oldNode; if (oldGraph != null && pool.Name != null && (oldNode = oldGraph.Nodes.Find(f => f.Name == pool.Name)) != null) { location = oldNode.Location; } directedGraphInfo.AddNode(pool.Name, ColourUtilities.ChooseColour(3), Color.Black, location); foreach (CarbonFlow cFlow in pool.FindAllChildren <CarbonFlow>()) { foreach (string destinationName in cFlow.destinationNames) { string destName = destinationName; if (destName == null) { destName = "Atmosphere"; needAtmosphereNode = true; } location = default(Point); Arc oldArc; if (oldGraph != null && pool.Name != null && (oldArc = oldGraph.Arcs.Find(f => f.SourceName == pool.Name && f.DestinationName == destName)) != null) { location = oldArc.Location; } directedGraphInfo.AddArc(null, pool.Name, destName, Color.Black, location); } } } foreach (Solute solute in this.FindAllChildren <Solute>()) { directedGraphInfo.AddNode(solute.Name, ColourUtilities.ChooseColour(2), Color.Black); foreach (NFlow nitrogenFlow in solute.FindAllChildren <NFlow>()) { string destName = nitrogenFlow.destinationName; if (destName == null) { destName = "Atmosphere"; needAtmosphereNode = true; } directedGraphInfo.AddArc(null, nitrogenFlow.sourceName, destName, Color.Black); } } if (needAtmosphereNode) { directedGraphInfo.AddTransparentNode("Atmosphere"); } directedGraphInfo.End(); }
/// <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; profileGrid.Attach(model, this.view.ProfileGrid, explorerPresenter); this.explorerPresenter = explorerPresenter; this.view.ShowView(false); // 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 { // The graph's series contain many variables such as [Soil].LL. We now replace // these relative paths with absolute paths. foreach (Series series in Apsim.Children(graph, typeof(Series))) { series.XFieldName = series.XFieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); series.X2FieldName = series.X2FieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); series.YFieldName = series.YFieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); series.Y2FieldName = series.Y2FieldName?.Replace("[Soil]", Apsim.FullPath(this.model.Parent)); } this.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(); for (int col = 0; col < this.propertiesInGrid.Count; col++) { string columnName = propertiesInGrid[col].ColumnName; if (columnName.Contains("\r\n")) { StringUtilities.SplitOffAfterDelimiter(ref columnName, "\r\n"); } // crop colours if (columnName.Contains("LL")) { Series cropLLSeries = new Series(); cropLLSeries.Name = columnName; cropLLSeries.Colour = ColourUtilities.ChooseColour(this.graph.Children.Count); cropLLSeries.Line = LineType.Solid; cropLLSeries.Marker = MarkerType.None; cropLLSeries.Type = SeriesType.Scatter; cropLLSeries.ShowInLegend = true; cropLLSeries.XAxis = Axis.AxisType.Top; cropLLSeries.YAxis = Axis.AxisType.Left; cropLLSeries.YFieldName = (parentForGraph is Soil ? Apsim.FullPath(parentForGraph) : "[Soil]") + ".DepthMidPoints"; cropLLSeries.XFieldName = Apsim.FullPath((propertiesInGrid[col].ObjectWithProperty as Model)) + "." + propertiesInGrid[col].PropertyName; //cropLLSeries.XFieldName = Apsim.FullPath(property.Object as Model) + "." + property.Name; cropLLSeries.Parent = this.graph; this.graph.Children.Add(cropLLSeries); } } explorerPresenter.ApsimXFile.Links.Resolve(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.CellsHaveChanged += this.OnProfileGridCellValueChanged; // Trap the right click on column header so that we can potentially put // units on the context menu. this.view.ProfileGrid.ColumnMenuClicked += this.OnColumnMenuItemClicked; // Trap the model changed event so that we can handle undo. this.explorerPresenter.CommandHistory.ModelChanged += this.OnModelChanged; this.view.ShowView(true); }