// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Drawing; using System.Linq; using System.Windows.Forms; using Core.Common.Base; using Core.Common.Controls.Views; using Core.Common.Gui.Commands; using Core.Common.Utils.Reflection; using Ringtoets.Common.Data.AssessmentSection; using Ringtoets.Common.Data.Calculation; using Ringtoets.Common.Data.Contribution; using Ringtoets.Common.Data.FailureMechanism; using CoreCommonBaseResources = Core.Common.Base.Properties.Resources; using CommonGuiResources = Core.Common.Gui.Properties.Resources; using RingtoetsIntegrationFormsResources = Ringtoets.Integration.Forms.Properties.Resources; namespace Ringtoets.Integration.Forms.Views { /// /// View for the , from which the /// can be updated and the /// and can be seen in a grid. /// public partial class FailureMechanismContributionView : UserControl, IView, IObserver { private readonly Observer isFailureMechanismRelevantObserver; private readonly Observer closeViewsForIrrelevantFailureMechanismObserver; private DataGridViewColumn probabilityPerYearColumn; private FailureMechanismContribution data; private bool revertingComboBoxSelectedValue; private IAssessmentSection assessmentSection; private DataGridViewCheckBoxColumn isRelevantColumn; /// /// Creates a new instance of . /// public FailureMechanismContributionView() { InitializeComponent(); InitializeGridColumns(); InitializeAssessmentSectionCompositionComboBox(); BindNormChange(); BindNormInputLeave(); SubscribeEvents(); isFailureMechanismRelevantObserver = new Observer(SetRowStyling); closeViewsForIrrelevantFailureMechanismObserver = new Observer(CloseViewsForIrrelevantFailureMechanism); Load += OnLoad; } /// /// Gets or sets the assessment section this view belongs to. /// public IAssessmentSection AssessmentSection { get { return assessmentSection; } set { HandleNewAssessmentSectionSet(value); } } public IViewCommands ViewCommands { private get; set; } public object Data { get { return data; } set { HandleNewDataSet((FailureMechanismContribution) value); } } public void UpdateObserver() { SetNormText(); probabilityDistributionGrid.Invalidate(); } /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } UnsubscribeEvents(); DetachFromFailureMechanisms(); ViewCommands = null; base.Dispose(disposing); } private void OnLoad(object sender, EventArgs e) { if (probabilityDistributionGrid.DataSource != null) { SetRowStyling(); } } private void InitializeAssessmentSectionCompositionComboBox() { assessmentSectionCompositionComboBox.DataSource = new[] { Tuple.Create(AssessmentSectionComposition.Dike, "Dijk"), Tuple.Create(AssessmentSectionComposition.Dune, "Duin"), Tuple.Create(AssessmentSectionComposition.DikeAndDune, "Dijk / Duin") }; assessmentSectionCompositionComboBox.ValueMember = TypeUtils.GetMemberName>(t => t.Item1); assessmentSectionCompositionComboBox.DisplayMember = TypeUtils.GetMemberName>(t => t.Item2); } private void SubscribeEvents() { probabilityDistributionGrid.CellFormatting += ProbabilityDistributionGridOnCellFormatting; } private void UnsubscribeEvents() { probabilityDistributionGrid.CellFormatting -= ProbabilityDistributionGridOnCellFormatting; } private void ProbabilityDistributionGridOnCellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { if (e.ColumnIndex == probabilityPerYearColumn.Index) { var contributionItem = data.Distribution.ElementAt(e.RowIndex); if (Math.Abs(contributionItem.Contribution) < 1e-6) { e.Value = RingtoetsIntegrationFormsResources.FailureMechanismContributionView_ProbabilityPerYear_Not_applicable; e.FormattingApplied = true; } } } private void HandleNewDataSet(FailureMechanismContribution value) { UnbindNormChange(); DetachFromData(); data = value; SetGridDataSource(); SetNormText(); AttachToData(); BindNormChange(); } private void HandleNewAssessmentSectionSet(IAssessmentSection value) { UnbindAssessmentSectionCompositionChange(); DetachFromFailureMechanisms(); assessmentSection = value; AttachToFailureMechanisms(); SetAssessmentSectionComposition(); BindAssessmentSectionCompositionChange(); } private void DetachFromFailureMechanisms() { if (assessmentSection != null) { foreach (IFailureMechanism failureMechanism in assessmentSection.GetFailureMechanisms()) { failureMechanism.Detach(isFailureMechanismRelevantObserver); failureMechanism.Detach(closeViewsForIrrelevantFailureMechanismObserver); } } } private void AttachToFailureMechanisms() { if (assessmentSection != null) { foreach (IFailureMechanism failureMechanism in assessmentSection.GetFailureMechanisms()) { failureMechanism.Attach(isFailureMechanismRelevantObserver); failureMechanism.Attach(closeViewsForIrrelevantFailureMechanismObserver); } } } private void CloseViewsForIrrelevantFailureMechanism() { if (ViewCommands != null) { var irrelevantFailureMechanisms = assessmentSection.GetFailureMechanisms().Where(failureMechanism => !failureMechanism.IsRelevant); foreach (var failureMechanism in irrelevantFailureMechanisms) { ViewCommands.RemoveAllViewsForItem(failureMechanism); } } } private void SetGridDataSource() { if (data != null) { probabilityDistributionGrid.DataSource = data.Distribution.Select(ci => new FailureMechanismContributionItemRow(ci)).ToArray(); SetRowStyling(); probabilityDistributionGrid.Invalidate(); } } private void AttachToData() { if (data != null) { data.Attach(this); } } private void DetachFromData() { if (data != null) { data.Detach(this); } } private void BindAssessmentSectionCompositionChange() { assessmentSectionCompositionComboBox.SelectedIndexChanged += AssessmentSectionCompositionComboBoxSelectedIndexChanged; } private void UnbindAssessmentSectionCompositionChange() { assessmentSectionCompositionComboBox.SelectedIndexChanged -= AssessmentSectionCompositionComboBoxSelectedIndexChanged; } private void BindNormChange() { normInput.ValueChanged += NormValueChanged; } private void UnbindNormChange() { normInput.ValueChanged -= NormValueChanged; } private void BindNormInputLeave() { normInput.Leave += NormInputLeave; } private void NormInputLeave(object sender, EventArgs e) { ResetTextIfEmtpy(); } private void NormValueChanged(object sender, EventArgs eventArgs) { data.Norm = Convert.ToInt32(normInput.Value); data.NotifyObservers(); } private void ResetTextIfEmtpy() { if (string.IsNullOrEmpty(normInput.Text)) { normInput.Text = string.Format("{0}", normInput.Value); } } private void SetNormText() { if (data != null) { normInput.Value = data.Norm; } } private void SetAssessmentSectionComposition() { if (AssessmentSection != null) { assessmentSectionCompositionComboBox.SelectedValue = AssessmentSection.Composition; } } private void InitializeGridColumns() { probabilityDistributionGrid.CurrentCellDirtyStateChanged += DataGridViewCurrentCellDirtyStateChanged; probabilityDistributionGrid.GotFocus += DataGridViewGotFocus; var columnNameFormat = "column_{0}"; var isRelevantName = TypeUtils.GetMemberName(fmci => fmci.IsRelevant); isRelevantColumn = new DataGridViewCheckBoxColumn { DataPropertyName = isRelevantName, HeaderText = CommonGuiResources.FailureMechanismContributionView_GridColumn_RelevancyFilter, Name = string.Format(columnNameFormat, isRelevantName), AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader }; var assessmentName = TypeUtils.GetMemberName(fmci => fmci.Assessment); var assessmentColumn = new DataGridViewTextBoxColumn { DataPropertyName = assessmentName, HeaderText = CommonGuiResources.FailureMechanismContributionView_GridColumn_Assessment, Name = string.Format(columnNameFormat, assessmentName), AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader, ReadOnly = true }; var contributionName = TypeUtils.GetMemberName(fmci => fmci.Contribution); var probabilityColumn = new DataGridViewTextBoxColumn { DataPropertyName = contributionName, HeaderText = CommonGuiResources.FailureMechanismContributionView_GridColumn_Contribution, Name = string.Format(columnNameFormat, contributionName), AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader, ReadOnly = true }; var probabilitySpaceName = TypeUtils.GetMemberName(fmci => fmci.ProbabilitySpace); probabilityPerYearColumn = new DataGridViewTextBoxColumn { DataPropertyName = probabilitySpaceName, HeaderText = CommonGuiResources.FailureMechanismContributionView_GridColumn_ProbabilitySpace, Name = string.Format(columnNameFormat, probabilitySpaceName), AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill, MinimumWidth = 100, DefaultCellStyle = { Format = "1/#,#" }, ReadOnly = true }; probabilityDistributionGrid.AutoGenerateColumns = false; probabilityDistributionGrid.Columns.AddRange(isRelevantColumn, assessmentColumn, probabilityColumn, probabilityPerYearColumn); } private void DataGridViewCurrentCellDirtyStateChanged(object sender, EventArgs e) { // Ensure checkbox values are directly committed DataGridViewColumn currentColumn = probabilityDistributionGrid.Columns[probabilityDistributionGrid.CurrentCell.ColumnIndex]; if (currentColumn is DataGridViewCheckBoxColumn) { probabilityDistributionGrid.CommitEdit(DataGridViewDataErrorContexts.Commit); } } private void DataGridViewGotFocus(object sender, EventArgs eventArgs) { probabilityDistributionGrid.BeginEdit(true); // Always start editing after setting the focus (otherwise data grid view cell dirty events are no longer fired when using the keyboard...) } private void AssessmentSectionCompositionComboBoxSelectedIndexChanged(object sender, EventArgs e) { if (revertingComboBoxSelectedValue) { return; } double[] originalFailureMechanismContributions = assessmentSection.GetFailureMechanisms().Select(fm => fm.Contribution).ToArray(); var dialogResult = MessageBox.Show(RingtoetsIntegrationFormsResources.FailureMechanismContributionView_ChangeComposition_Change_will_clear_calculation_output_accept_question, CoreCommonBaseResources.Confirm, MessageBoxButtons.OKCancel); if (dialogResult == DialogResult.OK) { assessmentSection.ChangeComposition((AssessmentSectionComposition) assessmentSectionCompositionComboBox.SelectedValue); SetGridDataSource(); ClearCalculationOutputForChangedContributions(originalFailureMechanismContributions); assessmentSection.NotifyObservers(); } else { revertingComboBoxSelectedValue = true; assessmentSectionCompositionComboBox.SelectedValue = assessmentSection.Composition; revertingComboBoxSelectedValue = false; } } private void ClearCalculationOutputForChangedContributions(double[] originalFailureMechanismContributions) { var allFailureMechanisms = assessmentSection.GetFailureMechanisms().ToArray(); for (int i = 0; i < allFailureMechanisms.Length; i++) { IFailureMechanism failureMechanism = allFailureMechanisms[i]; if (originalFailureMechanismContributions[i] != failureMechanism.Contribution) { foreach (ICalculation calculation in failureMechanism.Calculations) { calculation.ClearOutput(); calculation.NotifyObservers(); } } } } private void SetRowStyling() { foreach (DataGridViewRow row in probabilityDistributionGrid.Rows) { var isRelevantCell = (DataGridViewCheckBoxCell) row.Cells[isRelevantColumn.Index]; FailureMechanismContributionItem rowData = data.Distribution.ElementAt(row.Index); isRelevantCell.ReadOnly = rowData.IsAlwaysRelevant; var isFailureMechanismRelevant = (bool) isRelevantCell.Value; SetRowStyle(isFailureMechanismRelevant, row); } } private void SetRowStyle(bool checkboxSelected, DataGridViewRow row) { for (int i = 0; i < row.Cells.Count; i++) { if (i != isRelevantColumn.Index) { if (checkboxSelected) { SetCellStyle(row.Cells[i], Color.FromKnownColor(KnownColor.White), Color.FromKnownColor(KnownColor.ControlText)); } else { SetCellStyle(row.Cells[i], Color.FromKnownColor(KnownColor.DarkGray), Color.FromKnownColor(KnownColor.GrayText)); } } } } private void SetCellStyle(DataGridViewCell cell, Color backgroundColor, Color textColor) { cell.Style.BackColor = backgroundColor; cell.Style.ForeColor = textColor; } private class FailureMechanismContributionItemRow { private readonly FailureMechanismContributionItem item; public FailureMechanismContributionItemRow(FailureMechanismContributionItem item) { this.item = item; } public string Assessment { get { return item.Assessment; } } public double Contribution { get { return item.Contribution; } } public int Norm { get { return item.Norm; } } public double ProbabilitySpace { get { return item.ProbabilitySpace; } } public bool IsRelevant { get { return item.IsRelevant; } set { item.IsRelevant = value; item.NotifyFailureMechanismObservers(); } } } } }