// Copyright (C) Stichting Deltares 2025. All rights reserved.
//
// This file is part of the application DAM - UI.
//
// DAM - UI 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.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Deltares.Dam.Data;
using Deltares.Dam.Data.DamEngineIo;
using Deltares.Dam.Data.DataPlugins;
using Deltares.Dam.Data.DataPlugins.Configuration;
using Deltares.Dam.Data.IO;
using Deltares.Dam.Data.License;
using Deltares.Dam.Data.Sensors;
using Deltares.Dam.Data.UISupport;
using Deltares.DamEngine.Data.Standard;
using Deltares.DamEngine.Interface;
using Deltares.DamEngine.Io;
using Deltares.DamEngine.Io.XmlInput;
using Deltares.DamEngine.Io.XmlOutput;
using Deltares.Geotechnics.Mechanisms;
using Deltares.Geotechnics.SurfaceLines;
using Deltares.Standard;
using Deltares.Standard.Attributes;
using Deltares.Standard.Calculate;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.EventPublisher.Enum;
using Deltares.Standard.Forms;
using Deltares.Standard.Forms.DExpress;
using Deltares.Standard.Forms.Maps;
using Deltares.Standard.IO.Xml;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
using Deltares.Standard.Specifications;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Docking;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraTreeList.Nodes;
using ConversionHelper = Deltares.Dam.Data.DamEngineIo.ConversionHelper;
using Location = Deltares.Dam.Data.Location;
using Message = Deltares.DamEngine.Io.XmlOutput.Message;
using ProgressDelegate = Deltares.DamEngine.Data.Standard.Calculation.ProgressDelegate;
using Sensor = Deltares.Dam.Data.Sensors.Sensor;
using SensorLocation = Deltares.Dam.Data.Sensors.SensorLocation;
using Soil = Deltares.Geotechnics.Soils.Soil;
namespace Deltares.Dam.Forms
{
public class DamPlugin : IMainFormPlugin, IVisibleEnabled, IVisibleEnabledProvider, IDisposable
{
private readonly DamProject damProject = new DamProject();
private readonly LocationJobSymbol locationJobSymbol = new LocationJobSymbol();
private readonly Panel panel = new Panel();
private readonly Panel projectPanel = new Panel();
private readonly Panel materialPanel = new Panel();
private readonly Panel locationJobPanel = new Panel();
private readonly Panel calculationSpecificationPanel = new Panel();
private readonly Panel stabilityKernelTypeSpecificationPanel = new Panel();
private readonly Panel sensorPanel = new Panel();
private readonly GridViewControl locationsControl = new GridViewControl
{
Name = "Locations",
ShowToolbar = true,
HideUnusedColumns = true
};
private readonly GridViewControl calculationsControl = new GridViewControl
{
Name = "Calculations",
ShowToolbar = true,
HideUnusedColumns = true
};
private readonly GridViewControl designCalculationsControl = new GridViewControl
{
Name = "DesignCalculations",
ShowToolbar = true,
HideUnusedColumns = true,
SendSelectionChanged = true
};
private readonly GridViewControl sensorControl = new GridViewControl
{
Name = "Sensors",
ShowToolbar = true,
HideUnusedColumns = true,
SendSelectionChanged = false // Set to true when custom property editor is ready
};
private readonly GridViewControl sensorGroupControl = new GridViewControl
{
Name = "SensorGroups",
ShowToolbar = true,
HideUnusedColumns = true,
SendSelectionChanged = false // Set to true when custom property editor is ready
};
private readonly GridViewControl sensorProfileControl = new GridViewControl
{
Name = "SensorLocations",
ShowToolbar = true,
HideUnusedColumns = true,
SendSelectionChanged = true // To add/activate custom property editor when ready, see DataEventPublisher_OnSelectionChanged
};
private readonly DesignCalculationPropertyControl designCalculationPropertyControl = new DesignCalculationPropertyControl();
private readonly LocationPropertyControl locationPropertyControl = new LocationPropertyControl();
private readonly DamSurfaceLineControl damSurfaceLineControl = new DamSurfaceLineControl();
private readonly DamProjectCalculationSpecificationPropertyControl damProjectCalculationSpecificationPropertyControl = new DamProjectCalculationSpecificationPropertyControl();
private readonly DikePropertyControl dikePropertyControl = new DikePropertyControl();
private readonly BarButtonItem showCalculationOptionsItem = new BarButtonItem();
private readonly MapEditor mapControl = new MapEditor();
private MainForm mainForm;
private SpatialEditor spatialEditor;
private TreeViewControl damNavigator;
private DamMapEditor mapEditor;
private DamGeometryEditor geometryEditor;
private GridViewControl materialsTable;
private ProgressDelegate progressDelegate;
private bool initial = true;
private DAMNewProjectData damNewProjectData;
private CsvExportData lastDesignResult;
private LocationJob currentLocationJob;
public int MaxCalculationCores
{
get
{
if (mainForm == null)
{
return 1;
}
if (damProject != null && damProject.DamProjectData != null)
{
damProject.DamProjectData.MaxCalculationCores = mainForm.MaxCalculationCores;
}
return mainForm.MaxCalculationCores;
}
set
{
if (damProject != null && damProject.DamProjectData != null && damProject.DamProjectData.MaxCalculationCores != value)
{
damProject.DamProjectData.MaxCalculationCores = value;
}
if (mainForm != null)
{
mainForm.MaxCalculationCores = value;
}
}
}
[Browsable(false)] public bool StabilityKernelTypeSpecificationsVisible { get; set; }
[Label("Options")]
public void ShowCalculationOptions()
{
DataEventPublisher.SelectionChanged(damProject.DamProjectData.WaterBoardJob);
FormsSupport.MakeTreeVisible(damProjectCalculationSpecificationPropertyControl);
}
public void Dispose()
{
damProject.Dispose();
}
public void Configure(MainForm mainForm)
{
ConfigureSoilUserFilters();
this.mainForm = mainForm;
spatialEditor = mainForm.GeometryEditor.SpatialEditor;
mainForm.UseTemplateDialog = true;
mainForm.AllowMultiCoreSelection = true; // Switch to enable/disable multicore calculation for DAM
DamProject.ProjectWorkingPathLocation = ProjectPathLocation.InProjectMap;
RegisterFileHandlers();
RegisterUsedControls();
SetApplicationIcon();
ConfigureControls();
RegisterCalculation();
ConfigureMenu();
BindSupport.Assign(panel, this);
DataEventPublisher.OnAfterChange += DataEventPublisher_OnAfterChange;
DataEventPublisher.OnSelectionChanged += DataEventPublisher_OnSelectionChanged;
LocalizationManager.CultureChanged += (sender, args) => UpdateNavigatorTopItem();
// for backward compatibility
XmlHandler.RegisterObjectHandler(new FailureMechanismeParamatersMStabXmlHandler());
// This is to force the version type (Alpha, Pre-Alpha etc.) to be updated
mainForm.ReloadManager.ApplyCurrentUiCultureToAll();
// Set number of cores to 1 when multicore is not allowed
MaxCalculationCores = mainForm.AllowMultiCoreSelection ? MaxCalculationCores : 1;
mainForm.ProgramSettings.AllowMultiCoreSelection = mainForm.AllowMultiCoreSelection;
}
public void Assign(object source)
{
var projectData = source as DamProjectData;
if (projectData == null)
{
return;
}
initial = false;
// var args = Environment.GetCommandLineArgs();
// foreach (string arg in args)
// {
// if (arg.ToLower().Equals("-wti"))
// {
// projectData.DamProjectCalculationSpecification.VisibleEnabledProvider = this;
// StabilityKernelTypeSpecificationsVisible = true;
// }
// }
// For easy testing purposes, make sure kernel selection option is true
projectData.DamProjectCalculationSpecification.VisibleEnabledProvider = this;
// For now, make sure stability kernel selection is not possible. Enable this when 2019 is fully available.
StabilityKernelTypeSpecificationsVisible = false;
Context.CurrentContext = new DamContext
{
Wti = StabilityKernelTypeSpecificationsVisible
};
// get data
lastDesignResult = null;
currentLocationJob = null;
DataSourceManager.DataSources = projectData.DataSources;
DataSourceManager.Active = true;
DataSourceManager.CurrentSource = DataSourceSystemType.User;
DataSourceManager.StartListening();
BindSupport.Assign(damNavigator, projectData);
BindSupport.Assign(projectPanel, projectData);
Dike sd = projectData.WaterBoard.SelectedDike;
projectData.WaterBoard.SelectedDike = sd;
BindSupport.Assign(materialPanel, projectData.WaterBoard.SelectedDike);
BindSupport.Assign(sensorPanel, projectData);
BindSupport.Assign(calculationSpecificationPanel, projectData.DamProjectCalculationSpecification);
BindSupport.Assign(locationJobPanel, currentLocationJob);
if (projectData.SensorData != null)
{
SensorLocation.GetGroups = projectData.SensorData.GetGroups;
}
// TODO This seems awkward: what is the purpose of assigning DamProjectData to locationJobSymbol, all it uses projectdata for is to fire events...
locationJobSymbol.DamProjectData = projectData;
damProject.DamProjectData = projectData;
mapEditor.Project = projectData;
// Force update for Log
DataEventPublisher.DataListModified(LogManager.Messages);
RealTimeBackgroundValidator.Instance.Register(projectData);
lastDesignResult = null;
// Read the Waterlevel Timeseries
damProject.ImportWaterLevelTimeSeries();
if (projectData.DamProjectType == DamProjectType.DamLiveConfiguration)
{
((mainForm.DynamicImageControl.Parent.Parent) as DockPanel).Visibility= DockVisibility.Hidden;
mainForm.CalculationMenu.Visibility = BarItemVisibility.Never;
if (projectData.SensorData != null)
{
projectData.SensorData.UpdatePickSensorsForGroups();
}
}
if (projectData.DamProjectType == DamProjectType.Design)
{
mainForm.DynamicImageControl.TabIndex = 1;
((mainForm.DynamicImageControl.Parent.Parent) as DockPanel).Visibility= DockVisibility.Visible;
mainForm.UseImage(false);
mainForm.CalculationMenu.Visibility = BarItemVisibility.Always;
}
}
public bool IsVisible(string property)
{
return true;
}
public bool IsEnabled(string property)
{
switch (property)
{
case "ExecuteSurfacelinesExport":
return damProject != null && damProject.DamProjectData != null &&
damProject.DamProjectData.DamProjectType == DamProjectType.Design && damProject.DamProjectData.LocationJobs != null &&
damProject.DamProjectData.LocationJobs.Count > 0 && lastDesignResult != null;
case "ClearResults":
return damProject != null && damProject.DamProjectData != null &&
damProject.DamProjectData.HasResults();
case "ShowCalculationOptions":
return damProject != null &&
damProject.DamProjectData != null &&
damProject.DamProjectData.LocationJobs != null &&
damProject.DamProjectData.DamProjectType == DamProjectType.Design &&
damProject.DamProjectData.LocationJobs.Count > 0;
default: return true;
}
}
public bool IsVisible(object source, string property)
{
if (source is WaterBoard)
{
switch (property)
{
case "SelectedDike":
return StabilityKernelTypeSpecificationsVisible;
default:
return true;
}
}
return true;
}
public bool IsEnabled(object source, string property)
{
return true;
}
///
/// Make sure that the top item of the Navigator ("Waterschap") after translation is displayed properly.
///
private void UpdateNavigatorTopItem()
{
TreeListNode node = damNavigator.TreeList.Nodes.FirstNode;
if (node == null)
{
return;
}
var wb = TreeViewControl.GetInnerDataObject(node.Tag) as WaterBoardJob;
if (null != wb)
{
node.SetValue(0, wb.Name);
}
}
private void SetApplicationIcon()
{
try
{
var icon = new Icon(typeof(DamPlugin).Assembly.GetManifestResourceStream(
"Deltares.Dam.Forms.Resources.DAM_icon.ico"));
mainForm.UseIcon(icon);
}
catch (Exception)
{
// Kill exception for Windows XP if load fails
// Todo: Solve exception; see MWDAM-391
}
}
private void RegisterUsedControls()
{
mainForm.UseNavigation();
mainForm.UseSpatialEditor();
mainForm.UseProperties();
mainForm.UseOutput();
mainForm.UseImage();
mainForm.UseTables();
mainForm.UseValidation();
mainForm.AddControl(mapControl);
// mainForm.UseReport(); For now, do not use report [MWDAM-412].
}
private void ConfigureControls()
{
ConfigureMapEditor();
geometryEditor = new DamGeometryEditor(mainForm.GeometryEditor);
ConfigureNavigation();
ConfigurePropertyGrid();
ConfigureTable();
ConfigureSoilMechanisms();
}
private void ConfigureMapEditor()
{
mapEditor = new DamMapEditor(mapControl, locationJobSymbol);
mapControl.EnableSelectButton = true;
mapControl.EnableZoomToData = true;
mapControl.EnableZoomToSelection = true;
mapControl.EnableZoomRectangle = true;
}
private void RegisterCalculation()
{
CalculationManager.Instance.Register("DAM", ExecuteCalculation);
}
private void RegisterFileHandlers()
{
mainForm.RegisterNewFileHandler(NewProject);
mainForm.RegisterOpenFileHandler("damx", "DAMX Files (*.damx)|*.damx", OpenProject);
mainForm.RegisterSaveFileHandler("damx", "DAMX Files (*.damx)|*.damx", damProject.SaveXMLProject);
}
private object OpenProject(string fileName)
{
object damProjectData = damProject.OpenXMLProject(fileName);
if (LogManager.Messages.Count > 0)
{
string message = LocalizationManager.GetTranslatedText(this, "OpenProjectWarnings");
LocalizedMessageBox.ShowTranslatedText(mainForm, message);
}
return damProjectData;
}
private void ConfigurePropertyGrid()
{
DynamicPropertyControl dpc = mainForm.DynamicPropertyControl;
// deregister the ugly property control provided by the Geotechnics plugin
dpc.ClearRegistrationsForType(typeof(DamSoil));
dpc.BuildDelayedPropertyControlForTypes(() => PropertyControlFactory.GetPropertyControl(), typeof(DamSoil));
dpc.BuildPropertyControlTabForTypes(locationPropertyControl, typeof(Location), typeof(LocationJob));
dpc.BuildPropertyControlTabForTypes(new LocationScenariosControl(), typeof(Location), typeof(LocationJob));
dpc.BuildPropertyControlTabForTypes(damSurfaceLineControl, typeof(SurfaceLine2), typeof(CharacteristicPoint), typeof(LocationJob));
progressDelegate = dikePropertyControl.DoProgress;
dpc.BuildPropertyControlTabForTypes(dikePropertyControl, typeof(Dike), typeof(DikeJob));
dpc.BuildPropertyControlTabForTypes(damProjectCalculationSpecificationPropertyControl, typeof(DamProjectData));
dpc.BuildPropertyControlTabForTypes(designCalculationPropertyControl, typeof(CsvExportData), typeof(LocationJob));
}
private void ConfigureTable()
{
materialsTable = new GridViewControl
{
Name = "MaterialsGridViewControl",
CurrentContext = Context.CurrentContext,
AllowedUserColumnFilters = Soil.AllowedUserColumnFilters,
AllowInserts = true,
HideUnusedColumns = true,
AllowUserColumnFilterEdit = true
};
mainForm.RegisterTableControl(typeof(DamSoil), materialsTable, "Materials");
BindSupport.Bind(materialPanel, materialsTable, typeof(Dike), "DamSoils");
BindSupport.Bind(materialPanel, materialsTable.Parent, typeof(Dike), "DamSoils", BindingType.Visibility);
mainForm.DynamicTableControl.RegisterTable(typeof(Location), locationsControl, "Locations");
BindSupport.Bind(projectPanel, locationsControl, p => p.Locations);
mainForm.DynamicTableControl.RegisterTable(typeof(CsvExportData), designCalculationsControl, "Design calculations");
BindSupport.Bind(projectPanel, designCalculationsControl, p => p.DesignCalculations);
BindSupport.Bind(projectPanel, designCalculationsControl.Parent, p => p.DesignCalculations);
mainForm.DynamicTableControl.RegisterTable(typeof(Sensor), sensorControl, "Sensor Configuration");
BindSupport.Bind(sensorControl, sensorControl, p => p.Sensors);
BindSupport.Bind(sensorPanel, sensorControl, p => p.SensorData, BindingType.Assign);
BindSupport.Bind(sensorPanel, sensorControl.Parent, p => p.SensorData, BindingType.Visibility);
mainForm.DynamicTableControl.RegisterTable(typeof(Group), sensorGroupControl, "Sensor Group Configuration");
BindSupport.Bind(sensorGroupControl, sensorGroupControl, p => p.SensorGroups);
BindSupport.Bind(sensorPanel, sensorGroupControl, p => p.SensorData, BindingType.Assign);
BindSupport.Bind(sensorPanel, sensorGroupControl.Parent, p => p.SensorData, BindingType.Visibility);
mainForm.DynamicTableControl.RegisterTable(typeof(SensorLocation), sensorProfileControl, "Sensor Location Data");
BindSupport.Bind(sensorProfileControl, sensorProfileControl, p => p.SensorLocations);
BindSupport.Bind(sensorPanel, sensorProfileControl, p => p.SensorData, BindingType.Assign);
BindSupport.Bind(sensorPanel, sensorProfileControl.Parent, p => p.SensorData, BindingType.Visibility);
}
private void ConfigureSoilUserFilters()
{
Soil.AllowedUserColumnFilters = new[]
{
UserColumnFilters.MacrostabilityWti,
UserColumnFilters.PipingWti
};
}
private void ConfigureSoilMechanisms()
{
Soil.Mechanisms = new[]
{
Mechanism.DAM,
Mechanism.Piping,
Mechanism.PipingUpliftGradient,
Mechanism.Stability
};
MechanismSupport.Mechanisms = Soil.Mechanisms;
}
///
/// Adds the menus and their bind support.
///
private void ConfigureMenu()
{
var clearResultsMenuItem = new BarButtonItem
{
Caption = "Clear Results",
Name = "ClearResultsMenuItem"
};
var projectTypeComboBox = new RepositoryItemComboBox
{
TextEditStyle = TextEditStyles.DisableTextEditor
};
var projectTypeBarItem = new BarEditItem
{
Width = 100,
Edit = projectTypeComboBox,
PaintStyle = BarItemPaintStyle.Caption
};
var designAnalysisComboBox = new RepositoryItemComboBox
{
TextEditStyle = TextEditStyles.DisableTextEditor
};
var designAnalysisBarItem = new BarEditItem
{
Width = 130,
Edit = designAnalysisComboBox,
PaintStyle = BarItemPaintStyle.Caption
};
mainForm.CalculationMenu.AddItem(clearResultsMenuItem);
mainForm.CalculationMenu.AddItem(showCalculationOptionsItem);
mainForm.ToolBar.AddItems(new BarItem[]
{
projectTypeBarItem,
designAnalysisBarItem
});
var surfacelineExportItem = new BarButtonItem
{
Caption = "Surfacelines",
Hint = "Export surfacelines's to CSV files",
Name = "exportSurfaceLineBarItem"
};
mainForm.ExportMenu.AddItem(surfacelineExportItem);
mainForm.ExportMenu.Enabled = true;
var manualItem = new BarButtonItem
{
Caption = "Manual",
Name = "manualItem"
};
// Reorder the help menu bar
BarItemLink aboutItem = mainForm.HelpMenu.ItemLinks.First(bi => bi.Item.Name.Equals("HelpAboutItem"));
mainForm.HelpMenu.InsertItem(aboutItem, manualItem);
// Remove the link: Tools->License
BarItemLink licenseItemLink = mainForm.ToolsMenu.ItemLinks.First(il => il.Item.Name.Equals("LicenseBarButton"));
mainForm.ToolsMenu.ItemLinks.Remove(licenseItemLink);
BindSupport.Bind(panel, surfacelineExportItem, x => x.ExecuteSurfacelinesExport());
BindSupport.Bind(panel, clearResultsMenuItem, x => x.ClearResults());
BindSupport.Bind(panel, showCalculationOptionsItem, dp => dp.ShowCalculationOptions());
BindSupport.Bind(panel, manualItem, dp => GetUserManual());
BindSupport.Bind(projectPanel, projectTypeBarItem, x => x.DamProjectType, BindingType.LabelAndValue);
BindSupport.Bind(calculationSpecificationPanel, designAnalysisBarItem, x => DamProjectCalculationSpecification.SelectedAnalysisType, BindingType.LabelAndValue);
}
///
/// Gets the user manual.
///
private static void GetUserManual()
{
try
{
using var p = new Process();
p.StartInfo.FileName = @"Manual\DAM UI - User manual.pdf";
p.StartInfo.UseShellExecute = true;
p.Start();
}
catch (Win32Exception noBrowser)
{
if (noBrowser.ErrorCode == -2147467259)
{
MessageBox.Show(noBrowser.Message);
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
///
/// Export the redesigned surfacelines to a user selected folder
///
[Label("Surfacelines")]
private void ExecuteSurfacelinesExport()
{
var folderBrowserDialog = new FolderBrowserDialog();
folderBrowserDialog.SelectedPath = Path.GetDirectoryName(damProject.ProjectFileName);
if (String.IsNullOrEmpty(folderBrowserDialog.SelectedPath))
{
folderBrowserDialog.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
ExportRedesignedSurfacelines(folderBrowserDialog.SelectedPath);
}
}
[Label("Run")]
private void ExecuteCalculation()
{
if (DamLicense.DamLicenseType == DamLicenseType.None)
{
LocalizedMessageBox.ShowError(this, "NoLicenseGranted");
return;
}
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
mainForm.Invoke(new TaskDelegate(DataEventPublisher.SelectionChanged), damProject.DamProjectData.WaterBoard.SelectedDike);
LogManager.Clear();
damProject.DamProjectData.ClearResults();
});
DateTime startTimeCalculation = DateTime.Now;
TimeSpan elapsedTime;
damProject.DamProjectData.MaxCalculationCores = MaxCalculationCores;
string openingMessage = LocalizationManager.GetTranslatedText(this, "CalculationFinished");
string paragraphSepatator = Environment.NewLine + Environment.NewLine;
string timeMessage;
try
{
Input localInput = null;
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
Input input = FillXmlInputFromDamUi.CreateInput(damProject.DamProjectData);
localInput = input;
#if DEBUG
const string inputFilename = "InputFile.xml";
DamXmlSerialization.SaveInputAsXmlFile(inputFilename, localInput);
#endif
});
var damEngineInterface = new EngineInterface(localInput);
damEngineInterface.ProgressDelegate = progressDelegate;
string validationMessages = damEngineInterface.Validate();
if (!string.IsNullOrEmpty(validationMessages))
{
// The validation messages are deserialized. They are passed to the LogManager.
Output outputValidation = DamXmlSerialization.LoadOutputFromXmlString(validationMessages);
foreach (Message validationResult in outputValidation.ValidationResults)
{
LogManager.Add(new LogMessage(ConversionHelper.ConvertToMessageType(validationResult.MessageType), typeof(EngineInterface), validationResult.Message1));
}
foreach (Message calculationMessage in outputValidation.Results.CalculationMessages)
{
LogManager.Add(new LogMessage(ConversionHelper.ConvertToMessageType(calculationMessage.MessageType), typeof(EngineInterface), calculationMessage.Message1));
}
// If there are errors found throw an expection to stop calculation.
if (LogManager.Messages.Any(m => m.MessageType == LogMessageType.Error))
{
throw new Exception(LocalizationManager.GetTranslatedText(this, "ValidationErrorsOccurred"));
}
}
// There are no errors, so perform calculation.
if (!mainForm.AllowMultiCoreSelection)
{
// Multicore calculation not enabled
ThrowHelper.ThrowWhenConditionIsTrue(LocalizationManager.GetTranslatedText(this, "MultiCoreNotSupported"),
() => damEngineInterface.DamProjectData.MaxCalculationCores > 1);
}
string outputXml = damEngineInterface.Run();
Output output = DamXmlSerialization.LoadOutputFromXmlString(outputXml);
FillDamUiFromXmlOutput.AddOutputToDamProjectData(damProject.DamProjectData, output);
elapsedTime = DateTime.Now - startTimeCalculation;
timeMessage = String.Format(LocalizationManager.GetTranslatedText(this, "CalculationTime"), elapsedTime.ToString(@"dd\.hh\:mm\:ss"));
LocalizedMessageBox.ShowTranslatedText(mainForm, openingMessage + paragraphSepatator + timeMessage);
#if DEBUG
const string outputFilename = "OutputFile.xml";
DamXmlSerialization.SaveOutputAsXmlFile(outputFilename, output);
#endif
}
catch (Exception e)
{
elapsedTime = DateTime.Now - startTimeCalculation;
timeMessage = String.Format(LocalizationManager.GetTranslatedText(this, "CalculationTime"), elapsedTime.ToString(@"dd\.hh\:mm\:ss"));
LogManager.Add(new LogMessage(LogMessageType.FatalError, typeof(EngineInterface), string.Format("{0}", e.Message)));
openingMessage = LocalizationManager.GetTranslatedText(this, "CalculationFailed");
LocalizedMessageBox.ShowTranslatedText(mainForm, openingMessage + paragraphSepatator + timeMessage + paragraphSepatator + e.Message);
}
damProject.SaveXMLProject(damProject.ProjectFileName, damProject);
damProject.SaveCalculationLogToTextFile(damProject.DamProjectData.CalculationMessages, damProject.ProjectFileName);
SetProperControlsAfterCalculation();
}
private void SetProperControlsAfterCalculation()
{
if (damProject.DamProjectData.CalculationMessages != null && damProject.DamProjectData.CalculationMessages.Count > 0)
{
LogManager.Messages.AddRange(damProject.DamProjectData.CalculationMessages);
mainForm.Invoke(new PublisherDelegate(DataEventPublisher.DataListModified), LogManager.Messages, null);
}
SetProperControlsAfterDesignCalculation();
}
private void SetProperControlsAfterDesignCalculation()
{
LocationJob locationJob = damProject.DamProjectData.GetFirstLocationJobWithDesignResults();
if (locationJob != null)
{
CsvExportData res = locationJob.GetFirstDesignResult();
if (res != null)
{
mainForm.SetAsActiveTable(designCalculationsControl);
// Selecting the result sets the correct property editor as well as the correct line in the table.
try
{
mainForm.Invoke(new TaskDelegate(DataEventPublisher.SelectionChanged), res);
}
catch (Exception)
{
// when all calculations failed but some old result lingers (which it probably shouldn't) you trigger
// an event for a non existing designCalculationsControl. For now just ignore this error until it is clear
// how DAM should handle "old" results.
}
}
}
}
[Label("Clear Results")]
private void ClearResults()
{
DialogResult dialogResult = LocalizedMessageBox.Show(this, "ClearResultsQuestion", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dialogResult == DialogResult.Yes)
{
if ((damProject != null) && (damProject.DamProjectData != null))
{
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
try
{
damProject.DeleteResults();
lastDesignResult = null;
}
catch (Exception exception)
{
mainForm.Invoke(new ExceptionDelegate(ShowErrorMessageBox), exception);
}
finally
{
UpdateForDamApplicationType();
SetProperControlsAfterClearResults();
}
});
}
}
}
private void SetProperControlsAfterClearResults()
{
// update logmessages
mainForm.Invoke(new PublisherDelegate(DataEventPublisher.DataListModified), LogManager.Messages, null);
// update the data
mainForm.Invoke(new TaskDelegate(DataEventPublisher.SelectionChanged), damProject.DamProjectData.LocationJobs.FirstOrDefault());
mainForm.Invoke(new PublisherDelegate(DataEventPublisher.DataListModified), damProject.DamProjectData.LocationJobs, null);
mainForm.Invoke(new TaskDelegate(DataEventPublisher.SelectionChanged), damProject.DamProjectData.WaterBoard.Locations.FirstOrDefault());
// For design, extra action is needed to get rid of the calculation property window
if (damProject.DamProjectData.DamProjectType == DamProjectType.Design)
{
SetProperControlsAfterClearDesignResults();
}
// Set map for main window
mainForm.SetAsActiveTabOnMainPanel(mapControl);
// Set the locations table
mainForm.SetAsActiveTable(locationsControl);
}
private void SetProperControlsAfterClearDesignResults()
{
mainForm.Invoke(new PublisherDelegate(DataEventPublisher.AfterChange), damProject.DamProjectData.LocationJobs.FirstOrDefault(), null);
}
private void ConfigureNavigation()
{
damNavigator = new WaterBoardTreeView();
mainForm.NavigatorControl.RegisterResource(typeof(WaterBoard), damNavigator, "Waterboard");
BindSupport.Bind(projectPanel, damNavigator, typeof(DamProjectData), "WaterBoardJob");
}
private void DataEventPublisher_OnAfterChange(object sender, PublishEventArgs e)
{
if (sender is CsvExportData)
{
if (e.Property != null && e.Property.Equals("ExceptionMessage"))
{
string exceptionMessage = ((CsvExportData) sender).ExceptionMessage;
LocalizedMessageBox.ShowError(this, exceptionMessage);
}
}
else if (sender == locationJobSymbol)
{
if (e.Property != null && e.Property.Equals("CurrentScenarioType"))
{
DataEventPublisher.AfterChange(this);
}
}
else if (sender == damProject.DamProjectData)
{
if (e.Property != null && e.Property.Equals("DamProjectType"))
{
if (damProject.DamProjectData.WaterBoard != null)
{
DataEventPublisher.AfterChange(damProject.DamProjectData.WaterBoard);
DataEventPublisher.DataListModified(damProject.DamProjectData.Locations);
}
}
}
else if (sender == damProject.DamProjectData.WaterBoard)
{
try
{
damProject.ImportWaterLevelTimeSeries();
//locationJobSymbol.Update(damProject.DamProjectData.LocationJobs);
}
catch (TimeSerieSchemaValidationException exception)
{
LocalizedMessageBox.ShowError(this, exception.Message);
}
}
else if (sender == currentLocationJob && sender != null)
{
DataEventPublisher.AfterChange(this, "CurrentLocationJob");
}
else if (sender == materialsTable)
{
if (e.Property.Equals("SelectedFilter"))
{
var damContext = Context.CurrentContext as DamContext;
if (damContext != null)
{
damContext.SoilUserFilter = GetSoilUserFilterFromMaterialTable();
UpdatePropertyControl();
}
}
}
}
private void UpdatePropertyControl()
{
if (mainForm.DynamicPropertyControl != null && mainForm.DynamicPropertyControl.SelectedObject != null)
{
DataEventPublisher.AfterChange(mainForm.DynamicPropertyControl.SelectedObject);
}
}
private UserColumnFilters? GetSoilUserFilterFromMaterialTable()
{
string selectedFilterText = materialsTable.SelectedFilter.Text;
UserColumnFilters? selectedFilterValue;
try
{
selectedFilterValue = (UserColumnFilters) Enum.Parse(typeof(UserColumnFilters), selectedFilterText);
}
catch (ArgumentException)
{
// Filter "All" or not a valid member of the UserColumnFilters enumeration
selectedFilterValue = null;
}
return selectedFilterValue;
}
private void SelectWaterBoardJob(WaterBoardJob job)
{
DataEventPublisher.SelectionChanged(damProject.DamProjectData);
}
private void SelectLocationJob(LocationJob locationJob)
{
Location location = locationJob.Location;
DataEventPublisher.SelectionChanged(location, PropertyEditorReactionType.Ignore);
if (damProject.DamProjectData.DamProjectType == DamProjectType.Design)
{
Location designLocation = location;
if (lastDesignResult != null)
{
designLocation = damProject.DamProjectData.Locations.Find(x => x.Name == lastDesignResult.LocationName);
}
if (lastDesignResult == null || designLocation != location)
{
lastDesignResult = locationJob.GetFirstDesignResult();
DataEventPublisher.SelectionChanged(lastDesignResult, PropertyEditorReactionType.Ignore);
}
}
DataEventPublisher.AfterChange(this);
}
private LocationJob FirstMatchingLocationJob(Location location)
{
// get the first matching location job, if any
return damProject.DamProjectData.LocationJobs
.FirstOrDefault(job => job.Location == location);
}
private void SelectFirstMatchingLocationJobIfAny(Location location)
{
LocationJob locationJob = FirstMatchingLocationJob(location);
if (locationJob != null)
{
DataEventPublisher.SelectionChanged(locationJob);
}
}
private void SelectLocation(Location location)
{
SelectFirstMatchingLocationJobIfAny(location);
}
private void SelectDesignResult(CsvExportData result)
{
lastDesignResult = result;
locationJobSymbol.CurrentProfileName = result.ProfileName;
locationJobSymbol.CurrentScenarioName = result.ScenarioName;
locationJobSymbol.CurrentCalculation = result.StabilityModel.ToString();
Location location = damProject.DamProjectData.Locations.Find(x => x.Name == lastDesignResult.LocationName);
if (location != null)
{
SelectFirstMatchingLocationJobIfAny(location);
}
DataEventPublisher.AfterChange(this);
}
private void DataEventPublisher_OnSelectionChanged(object sender, PublishEventArgs e)
{
Type type = sender == null ? null : sender.GetType();
if (((SelectionEventArgs) e).PropertyEditorReactionType != PropertyEditorReactionType.Ignore)
{
if (sender is WaterBoardJob)
{
SelectWaterBoardJob((WaterBoardJob) sender);
}
else if (sender is LocationJob)
{
currentLocationJob = (LocationJob) sender;
SelectLocationJob(currentLocationJob);
BindSupport.Assign(locationJobPanel, currentLocationJob);
DataEventPublisher.AfterChange(this, "CurrentLocationJob");
}
else if (sender is Location)
{
SelectLocation((Location) sender);
}
else if (sender is SensorLocation)
{
var senderLocation = (SensorLocation) sender;
SelectLocation(senderLocation.Location);
// Activate any custom property editor for SensorLocation here.
}
else if (sender is CsvExportData)
{
SelectDesignResult((CsvExportData) sender);
}
}
}
private void ShowImage(string file)
{
if (!String.IsNullOrEmpty(file))
{
mainForm.DynamicImageControl.ZoomablePictureBox.Image
= File.Exists(file) ? Image.FromFile(file) : null;
}
else
{
mainForm.DynamicImageControl.ZoomablePictureBox.Image = null;
}
}
private void UpdateForDamApplicationType()
{
Assign(damProject.DamProjectData);
}
private object NewProject()
{
if (initial)
{
initial = false;
return new DamProjectData();
}
damNewProjectData = new DAMNewProjectData
{
DamProjectType = DamProjectType.Design,
DamDataSourceFileName = damProject.DamProjectData.DamDataSourceFileName
};
var dlg = new DamNewProjectDialog
{
DamNewProjectData = damNewProjectData
};
dlg.Visible = false;
if (dlg.ShowDialog() == DialogResult.OK)
{
damProject.ClearProject();
damProject.ProjectFileName = dlg.DamNewProjectData.DamProjectFileName;
damProject.DamProjectData.DataSourceEsriProjection = dlg.DamNewProjectData.DataSourceEsriProjection;
CalculationManager.Instance.RunCalculation(Import);
mainForm.FileName = damProject.ProjectFileName;
mainForm.SetMainWindowCaption(damProject.ProjectFileName);
}
return damProject;
}
private void Import()
{
LogManager.Clear();
damProject.DamProjectData.WaterBoard.SelectedDike = new Dike();
mainForm.Invoke(new TaskDelegate(DataEventPublisher.SelectionChanged), damProject.DamProjectData.WaterBoard.SelectedDike);
progressDelegate(0);
Application.UseWaitCursor = true;
try
{
LogManager.Clear();
DamProjectType projectType = damNewProjectData.DamProjectType;
string fileName = damNewProjectData.DamDataSourceFileName;
DataSourceContainer dataSourceContainer = DataSourceContainer.Deserialize(fileName);
string damProjectFolder = Path.GetDirectoryName(fileName);
dataSourceContainer.DataSourceEsriProjection = dataSourceContainer.DataSourceEsriProjection ?? damNewProjectData.DataSourceEsriProjection;
DataEventPublisher.ThreadPublisher = new ThreadPublisher();
// ATTENTION: Do not stop DataEventPublisher because it is needed to determine the source of the data with DataSourceManager
DataSourceManager.StartListening();
damProject.Import(damProjectFolder, dataSourceContainer, damNewProjectData.SelectedDikeRingIds,
damNewProjectData.DamProjectType, progressDelegate);
// Importing data creates a new DamProjectData object so the values set in the dialog have to be reset.
damProject.DamProjectData.DamProjectType = projectType;
damProject.DamProjectData.DamDataSourceFileName = fileName;
if (dataSourceContainer.MapSoilProfile2D != null)
{
// Make sure the 2D-geometrie map is assigned
damProject.AssignGeometry2DMapnameIfNotAssigned(Path.Combine(damProjectFolder, dataSourceContainer.MapSoilProfile2D));
}
// If profiles are defined as relative profiles, new absolute profiles will be generated for each location
if (dataSourceContainer.IsImportAsRelativeProfiles)
{
WaterBoardPostProcessRelativeProfiles.CreateAbsoluteProfiles(damProject.DamProjectData.WaterBoard, dataSourceContainer.SoilProfileCharacteristicPointReference);
}
damProject.DamProjectData.DataSources = DataSourceManager.DataSources;
// Read sensor data if DamLive Configuration project
if (damNewProjectData.DamProjectType == DamProjectType.DamLiveConfiguration)
{
if (damProject.DamProjectData.WaterBoard.Dikes.Count != 1)
{
throw new DataPluginImporterException(String.Format("DamLive Configuration must have exactly 1 dike; this project has {0} dikes", damProject.DamProjectData.WaterBoard.Dikes.Count));
}
Dike dike = damProject.DamProjectData.WaterBoard.Dikes.First();
string sensorConfigurationFilename = Path.GetFullPath(damNewProjectData.SensorConfigurationFileName);
if (File.Exists(sensorConfigurationFilename))
{
SensorImportFromExcelSheet.ReadSensorDataFromExcel(sensorConfigurationFilename, dike);
damProject.DamProjectData.FillOverallSensorData();
}
}
// Save the data
damProject.SaveXMLProject(damProject.ProjectFileName, damProject);
damProject.SaveCalculationLogToTextFile(damProject.DamProjectData.CalculationMessages, damProject.ProjectFileName);
progressDelegate(1);
mainForm.Invoke(new EmptyDelegate(UpdateForDamApplicationType));
mainForm.Invoke(new TaskDelegate(DataEventPublisher.SelectionChanged), damProject.DamProjectData.LocationJobs.FirstOrDefault());
DataEventPublisher.TransferBindingsToDefaultPublisher();
}
catch (Exception e)
{
Application.UseWaitCursor = false;
mainForm.Invoke(new ExceptionDelegate(ShowImportErrorMessage), e);
}
finally
{
Application.UseWaitCursor = false;
}
}
///
/// General error message
///
///
///
private void ShowErrorMessageBox(Exception e)
{
var stringBuilder = new StringBuilder(e.Message + Environment.NewLine);
Exception exception = e.InnerException;
while (exception != null)
{
stringBuilder.AppendLine(exception.Message + Environment.NewLine);
exception = exception.InnerException;
}
var args = new object[]
{
stringBuilder.ToString()
};
LocalizedMessageBox.ShowError(this, "ErrorMessage", args);
}
///
/// Show import error messages
///
///
private void ShowImportErrorMessage(Exception e)
{
var stringBuilder = new StringBuilder(e.Message + Environment.NewLine);
Exception exception = e.InnerException;
while (exception != null)
{
stringBuilder.Append(exception.Message + Environment.NewLine);
exception = exception.InnerException;
}
var args = new object[]
{
Environment.NewLine,
damNewProjectData.DamDataSourceFileName,
Environment.NewLine + Environment.NewLine,
Environment.NewLine,
stringBuilder.ToString()
};
LocalizedMessageBox.ShowError(this, "ErrorImportingDataSourceFile", args);
}
///
/// Export the redesigned surfacelines
///
///
private void ExportRedesignedSurfacelines(string path)
{
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
string baseFilename = Path.Combine(path,
Path.GetFileNameWithoutExtension(damProject.ProjectFileName));
List exportListCharacteristicPoints;
List exportListSurfaceLines;
// Build list (for piping) of redesigsurfacelines and list of surfacelines with charateristic points and write them
exportListCharacteristicPoints = new List();
exportListSurfaceLines = new List();
var newlyCreatedSurfaceLines = new List();
foreach (CsvExportData designResult in damProject.DamProjectData.DesignCalculations)
{
SurfaceLine2 redesignedSurfaceLinePipingGlobal = designResult.CreateRedesignedSurfaceLineGlobal();
if (redesignedSurfaceLinePipingGlobal != null)
{
newlyCreatedSurfaceLines.Add(redesignedSurfaceLinePipingGlobal);
// Identifiers
CsvExportSurfaceLineIdentifiers csvExportSurfaceLineIdentifiers = CreateCsvExportSurfaceLineIdentifiers(designResult);
// Characteristic points
exportListCharacteristicPoints.Add(new CsvExportCharacteristicPoints(csvExportSurfaceLineIdentifiers, redesignedSurfaceLinePipingGlobal));
// Surfaceline
exportListSurfaceLines.Add(new CsvExportSurfaceLine(csvExportSurfaceLineIdentifiers, redesignedSurfaceLinePipingGlobal));
}
}
if (exportListCharacteristicPoints.Count > 0)
{
WriteSurfacelines(baseFilename + "_Piping", exportListSurfaceLines, exportListCharacteristicPoints);
}
foreach (SurfaceLine2 newlyCreatedGlobalSurfaceLine in newlyCreatedSurfaceLines)
{
newlyCreatedGlobalSurfaceLine.Dispose();
}
newlyCreatedSurfaceLines.Clear();
// Build list (for stability) of redesigsurfacelines and list of surfacelines with charateristic points and write them
exportListCharacteristicPoints = new List();
exportListSurfaceLines = new List();
foreach (CsvExportData designResult in damProject.DamProjectData.DesignCalculations)
{
SurfaceLine2 globalRedesignedSurfaceLine = designResult.CreateRedesignedSurfaceLineGlobal();
if (globalRedesignedSurfaceLine != null)
{
newlyCreatedSurfaceLines.Add(globalRedesignedSurfaceLine);
// Identifiers
CsvExportSurfaceLineIdentifiers csvExportSurfaceLineIdentifiers = CreateCsvExportSurfaceLineIdentifiers(designResult);
// Characteristic points
exportListCharacteristicPoints.Add(new CsvExportCharacteristicPoints(csvExportSurfaceLineIdentifiers, globalRedesignedSurfaceLine));
// Surfaceline
exportListSurfaceLines.Add(new CsvExportSurfaceLine(csvExportSurfaceLineIdentifiers, globalRedesignedSurfaceLine));
}
}
if (exportListCharacteristicPoints.Count > 0)
{
WriteSurfacelines(baseFilename + "_Stability", exportListSurfaceLines, exportListCharacteristicPoints);
}
foreach (SurfaceLine2 newlyCreatedGlobalSurfaceLine in newlyCreatedSurfaceLines)
{
newlyCreatedGlobalSurfaceLine.Dispose();
}
newlyCreatedSurfaceLines.Clear();
});
}
///
/// Creates the CSV export surfaceline identifiers, based on the designresult.
///
/// The design result.
///
private static CsvExportSurfaceLineIdentifiers CreateCsvExportSurfaceLineIdentifiers(CsvExportData designResult)
{
var csvExportSurfaceLineIdentifiers = new CsvExportSurfaceLineIdentifiers
{
LocationId = designResult.LocationName,
SoilProfileId = designResult.ProfileName,
Scenario = designResult.LocationScenarioId,
CalculationMechanism = designResult.DamFailureMechanismeCalculation.FailureMechanismSystemType.ToString(),
CalculationModel = ""
};
switch (designResult.DamFailureMechanismeCalculation.FailureMechanismSystemType)
{
case FailureMechanismSystemType.StabilityOutside:
csvExportSurfaceLineIdentifiers.CalculationModel =
designResult.DamFailureMechanismeCalculation.StabilityModelType.ToString();
break;
case FailureMechanismSystemType.StabilityInside:
csvExportSurfaceLineIdentifiers.CalculationModel =
designResult.DamFailureMechanismeCalculation.StabilityModelType.ToString();
break;
case FailureMechanismSystemType.Piping:
csvExportSurfaceLineIdentifiers.CalculationModel =
designResult.DamFailureMechanismeCalculation.PipingModelType.ToString();
break;
}
return csvExportSurfaceLineIdentifiers;
}
///
/// Writes the surfacelines.
///
/// The base filename.
/// The export list of surface lines.
/// The export list of characteristic points of the surface lines.
private void WriteSurfacelines(string baseFilename, List exportListSurfaceLines, List exportListCharacteristicPoints)
{
// Export lines with characteristic points
string fileNameCharacteristicPoints = baseFilename + "_CharacteristicPoints.csv";
var characteristicPointCsvExporter = new CsvExporter(
Path.Combine(baseFilename, fileNameCharacteristicPoints), exportListCharacteristicPoints)
{
WriteHeaderInFirstLine = true
};
characteristicPointCsvExporter.WriteFile();
// Export surfacelines
string fileNameSurfaceline = baseFilename + "_Surfacelines.csv";
var surfacelineCsvExporter = new CsvExporter(Path.Combine(
baseFilename, fileNameSurfaceline), exportListSurfaceLines)
{
WriteHeaderInFirstLine = true
};
surfacelineCsvExporter.WriteFile();
}
}
}