Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Appenders/RiskeerUserDataFolderConverter.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Attributes/DynamicPropertyOrderAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Attributes/DynamicPropertyOrderEvaluationMethodAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Attributes/DynamicReadOnlyAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Attributes/DynamicReadOnlyValidationMethodAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Attributes/DynamicVisibleAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Attributes/DynamicVisibleValidationMethodAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Attributes/PropertyOrderAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Clipboard/ClipboardProvider.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Clipboard/IClipboard.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Clipboard/SystemClipboard.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/ApplicationFeatureCommandHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/GuiExportHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/GuiImportHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/GuiUpdateHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/IApplicationFeatureCommands.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/ICommandsOwner.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/IExportCommandHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/IImportCommandHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/IStorageCommands.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/IUpdateCommandHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/IViewCommands.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/StorageCommandHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Commands/ViewCommandHandler.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ContextMenu/ContextMenuBuilder.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ContextMenu/ContextMenuBuilderException.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ContextMenu/GuiContextMenuItemFactory.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ContextMenu/IContextMenuBuilder.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ContextMenu/IContextMenuBuilderProvider.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ContextMenu/StrictContextMenuItem.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ContextMenu/TreeViewContextMenuItemFactory.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Converters/ColorTypeConverter.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Converters/ExpandableArrayConverter.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Converters/ExpandableReadOnlyArrayConverter.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Converters/KeyValueElementAttribute.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Converters/KeyValueExpandableArrayConverter.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Converters/PngToIconConverter.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ExceptionDialog.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ExceptionDialog.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ExceptionDialog.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MainWindow/IMainWindow.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindowCommands.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/IMessageWindow.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/MessageWindow.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/MessageWindow.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/MessageWindow.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/MessageWindowDialog.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/MessageWindowDialog.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/MessageWindowDialog.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/MessageWindow/MessageWindowLogAppender.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProgressDialog/ActivityProgressDialog.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProgressDialog/ActivityProgressDialog.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProgressDialog/ActivityProgressDialog.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProgressDialog/ActivityProgressDialogRunner.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProjectExplorer/IProjectExplorer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProjectExplorer/ProjectExplorer.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProjectExplorer/ProjectExplorer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ProjectExplorer/ProjectExplorer.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/PropertyGridView/IPropertyResolver.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/PropertyGridView/PropertyGridView.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/PropertyGridView/PropertyResolver.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/RichTextFile.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/RichTextView.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/RichTextView.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/RichTextView.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SelectItemDialog.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SelectItemDialog.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SelectItemDialog.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SelectViewDialog.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SelectViewDialog.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SelectViewDialog.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SplashScreen/SplashScreen.xaml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/SplashScreen/SplashScreen.xaml.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewHost/AvalonDockViewHost.xaml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewHost/AvalonDockViewHost.xaml.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewHost/DocumentViewController.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewHost/IDocumentViewController.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewHost/IViewHost.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewHost/ToolViewLocation.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewHost/ViewChangeEventArgs.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/GuiCore.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Helpers/DialogBasedInquiryHelper.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Helpers/ExportHelper.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Helpers/IInquiryHelper.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/IGui.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/IMainWindowController.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/IPluginsHost.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/IProjectOwner.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/IViewController.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/OpenProjectActivity.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/OptionalStepResult.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Plugin/ExportInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Plugin/ImportInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Plugin/PluginBase.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Plugin/PropertyInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Plugin/UpdateInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Plugin/ViewInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Properties/AssemblyInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Properties/Resources.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Properties/Resources.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/PropertyBag/DynamicPropertyBag.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/PropertyBag/IObjectProperties.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/PropertyBag/ObjectProperties.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpec.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpecDescriptor.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/PropertyBag/ReadOnlyPropertyDescriptorDecorator.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Core/Common/src/Core.Common.Gui/Resources/Busy indicator.gif =================================================================== diff -u -r231804c353b32db8e1421cfb776801a9b0677541 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/Copy.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/CopyHS.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/DeleteHS.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/Paste.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/PasteLarge.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/PropertiesHS.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/Riskeer.ico =================================================================== diff -u -r509c1ddd049c0a676090c72e85ce626cf14c2616 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/SplashScreenBackground.png =================================================================== diff -u -r304c5ea85834447d46c854cad8e467ce51e8218a -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/application_import_blue.ico =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/application_import_blue.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/application_view_list.png =================================================================== diff -u -rda63d908419d12dd724c7213564b7c11b44da391 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/arrow-000-medium-question-mark.ico =================================================================== diff -u -ra600b08ffb5dac8164691824fe6dc7f4e96814d0 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/arrow-000-medium.png =================================================================== diff -u -rda4d097a3f50554dda0bb688e187c2be8003de9f -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/arrow-stop-090.png =================================================================== diff -u -re388ea76d1d044298cc89156c8744fbea1bcb736 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/arrow-stop-270.png =================================================================== diff -u -re388ea76d1d044298cc89156c8744fbea1bcb736 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/arrow.png =================================================================== diff -u -re6e92cb42b1e4983add2406300958b6b116ba781 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/brick.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/broom.png =================================================================== diff -u -rb6f4e414fc874653cc6ad84b80f330b28e69b823 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/bug-exclamation.ico =================================================================== diff -u -rd372f6daa918d18feb719e78d5fdc315f2a1b0f5 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/error.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/exclamation.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/folder.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/icon_clear_all_messages.PNG =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/information.png =================================================================== diff -u -reee6c7815d1e418eac38c1c552fb279c0887ef55 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/key.png =================================================================== diff -u -r12c5ceb5471938a64061362a809cab802f00eb30 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/project-16.png =================================================================== diff -u -r1eed3e3f652618c52a462edc502cfd4250772314 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/project_explorer.png =================================================================== diff -u -rda63d908419d12dd724c7213564b7c11b44da391 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/properties_panel.png =================================================================== diff -u -rda63d908419d12dd724c7213564b7c11b44da391 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/table-export.png =================================================================== diff -u -ra85e384df91356b2c2716591531a863e01da876b -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/table-import.png =================================================================== diff -u -ra85e384df91356b2c2716591531a863e01da876b -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/table_refresh.png =================================================================== diff -u -r45440093089496f59ed420e772136756c229e30b -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/textfield_rename.png =================================================================== diff -u -r80393d2db0b9788fbedadf667391f67f014086e4 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Common/src/Core.Common.Gui/Resources/warning.ico =================================================================== diff -u -r156d0459ae98bc7a79b056e7b62dccbf3455995c -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/SaveProjectActivity.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Selection/IApplicationSelection.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Settings/GuiCoreSettings.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Settings/ISettingsOwner.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Style/DeltaresButtonStyle.xaml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Style/DeltaresGeneralStyle.xaml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Style/DeltaresStyle.xaml'. Fisheye: No comparison available. Pass `N' to diff? Index: Core/Common/src/Core.Common.Gui/Style/Symbols/Deltares-Riskeer-Symbols.ttf =================================================================== diff -u -r9add737a1f5217faea000bb9ac0bc2a7897707ab -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Style/Symbols/RiskeerSymbols.xaml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/UITypeEditors/ColorEditor.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/UITypeEditors/SelectionEditor.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 434415295de74c310ce6d3cdd0100c28838cf9ea refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/ViewPropertyEditor.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Core/Common/src/Core.Common.Gui/nl/Xceed.Wpf.AvalonDock.resources.dll =================================================================== diff -u -r5a2f411b10f2f7d2ab2f5056c9437a11b52a2543 -r434415295de74c310ce6d3cdd0100c28838cf9ea Binary files differ Index: Core/Gui/src/Core.Gui/Appenders/RiskeerUserDataFolderConverter.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Appenders/RiskeerUserDataFolderConverter.cs (revision 0) +++ Core/Gui/src/Core.Gui/Appenders/RiskeerUserDataFolderConverter.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,39 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.IO; +using Core.Common.Util.Settings; +using log4net.Util; + +namespace Core.Gui.Appenders +{ + /// + /// Converter that injects the application user data folder. + /// + public class RiskeerUserDataFolderConverter : PatternConverter // NOTE: Class might look like it's only used in tests, but it's actually created in Application.Riskeer/app.config! + { + protected override void Convert(TextWriter writer, object state) + { + string settingsDirectory = SettingsHelper.Instance.GetApplicationLocalUserSettingsDirectory(Option); + writer.Write(settingsDirectory); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Attributes/DynamicPropertyOrderAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Attributes/DynamicPropertyOrderAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Attributes/DynamicPropertyOrderAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,82 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Reflection; +using Core.Gui.Properties; + +namespace Core.Gui.Attributes +{ + /// + /// Marks property as a conditionally ordered property. When this attribute is declared + /// on a property, the declaring class should have a public method marked with + /// to be used to evaluate the + /// order of the property. + /// + /// + /// + /// This attribute provides a run-time alternative to . + [AttributeUsage(AttributeTargets.Property)] + public sealed class DynamicPropertyOrderAttribute : Attribute + { + /// + /// Determines the order of the property. + /// + /// The object. + /// The name of the property of . + /// The order of the property. + /// Thrown when + /// does not correspond to a public property of . + /// Thrown when there isn't a single method + /// declared on marked with + /// that is matching the signature defined by . + public static int PropertyOrder(object obj, string propertyName) + { + if (string.IsNullOrEmpty(propertyName)) + { + return 0; + } + + if (!IsPropertyDynamicOrdered(obj, propertyName)) + { + return 0; + } + + DynamicPropertyOrderEvaluationMethodAttribute.PropertyOrder propertyOrder = DynamicPropertyOrderEvaluationMethodAttribute.CreatePropertyOrderMethod(obj); + + return propertyOrder(propertyName); + } + + private static bool IsPropertyDynamicOrdered(object obj, string propertyName) + { + MemberInfo propertyInfo = obj.GetType().GetProperty(propertyName); + if (propertyInfo == null) + { + throw new MissingMemberException(string.Format(CultureInfo.CurrentCulture, + Resources.Could_not_find_property_0_on_type_1_, + propertyName, obj.GetType())); + } + + return IsDefined(propertyInfo, typeof(DynamicPropertyOrderAttribute)); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Attributes/DynamicPropertyOrderEvaluationMethodAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Attributes/DynamicPropertyOrderEvaluationMethodAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Attributes/DynamicPropertyOrderEvaluationMethodAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,118 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Linq; +using System.Reflection; +using CoreCommonGuiResources = Core.Gui.Properties.Resources; + +namespace Core.Gui.Attributes +{ + /// + /// Marks a method to be used to determine the order of a property. The method + /// should be public and have the signature of . + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class DynamicPropertyOrderEvaluationMethodAttribute : Attribute + { + /// + /// Required method signature when marking a method with . + /// + /// The name of the property to be checked. + /// The order of the property. + public delegate int PropertyOrder(string propertyName); + + /// + /// Creates a delegate that can be used to determine the order of a property. + /// + /// The object instance declaring the evaluation method. + /// The delegate. + /// Thrown when there isn't a single method + /// declared on marked with + /// that is matching the signature defined by . + public static PropertyOrder CreatePropertyOrderMethod(object target) + { + MethodInfo methodInfo = GetPropertyOrderMethod(target); + ValidateMethodInfo(methodInfo); + return CreatePropertyOrderDelegate(target, methodInfo); + } + + private static PropertyOrder CreatePropertyOrderDelegate(object target, MethodInfo methodInfo) + { + return (PropertyOrder) Delegate.CreateDelegate(typeof(PropertyOrder), target, methodInfo); + } + + private static void ValidateMethodInfo(MethodInfo methodInfo) + { + if (methodInfo.ReturnType != typeof(int)) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicPropertyOrderEvaluationMethod_must_return_int_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + if (parameterInfos.Length != 1) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicPropertyOrderEvaluationMethod_incorrect_argument_count_must_be_one_string_argument_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + + if (parameterInfos[0].ParameterType != typeof(string)) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicPropertyOrderEvaluationMethod_must_have_string_argument_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + } + + private static MethodInfo GetPropertyOrderMethod(object obj) + { + MethodInfo[] propertyOrderMethods = obj.GetType().GetMethods() + .Where(methodInfo => IsDefined(methodInfo, typeof(DynamicPropertyOrderEvaluationMethodAttribute))) + .ToArray(); + + if (propertyOrderMethods.Length == 0) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicPropertyOrderEvaluationMethod_not_found_or_not_public_on_Class_0_, + obj.GetType()); + throw new MissingMethodException(message); + } + + if (propertyOrderMethods.Length > 1) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicPropertyOrderEvaluationMethod_only_one_allowed_per_Class_0_, + obj.GetType()); + throw new MissingMethodException(message); + } + + return propertyOrderMethods[0]; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Attributes/DynamicReadOnlyAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Attributes/DynamicReadOnlyAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Attributes/DynamicReadOnlyAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,82 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Globalization; +using System.Reflection; +using Core.Gui.Properties; + +namespace Core.Gui.Attributes +{ + /// + /// Marks property as a conditional read-only property. When this attribute is declared + /// on a property, the declaring class should have a public method marked with + /// to be used to evaluate if + /// that property should be read-only or not. + /// + /// + /// + /// This attribute provides a run-time alternative to . + [AttributeUsage(AttributeTargets.Property)] + public sealed class DynamicReadOnlyAttribute : Attribute + { + /// + /// Determines whether the property is read-only or not. + /// + /// The object. + /// The name of the property of . + /// true if the property is read-only, false otherwise. + /// Thrown when + /// does not correspond to a public property of . + /// Thrown when there isn't a single method + /// declared on marked with + /// that is matching the signature defined by . + public static bool IsReadOnly(object obj, string propertyName) + { + if (string.IsNullOrEmpty(propertyName)) + { + return ReadOnlyAttribute.Default.IsReadOnly; + } + + if (!IsPropertyDynamicallyReadOnly(obj, propertyName)) + { + return ReadOnlyAttribute.Default.IsReadOnly; + } + + DynamicReadOnlyValidationMethodAttribute.IsPropertyReadOnly isPropertyReadOnlyDelegate = DynamicReadOnlyValidationMethodAttribute.CreateIsReadOnlyMethod(obj); + return isPropertyReadOnlyDelegate(propertyName); + } + + private static bool IsPropertyDynamicallyReadOnly(object obj, string propertyName) + { + MemberInfo propertyInfo = obj.GetType().GetProperty(propertyName); + if (propertyInfo == null) + { + throw new MissingMemberException(string.Format(CultureInfo.CurrentCulture, + Resources.Could_not_find_property_0_on_type_1_, + propertyName, obj.GetType())); + } + + return IsDefined(propertyInfo, typeof(DynamicReadOnlyAttribute)); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Attributes/DynamicReadOnlyValidationMethodAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Attributes/DynamicReadOnlyValidationMethodAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Attributes/DynamicReadOnlyValidationMethodAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,118 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Linq; +using System.Reflection; +using CoreCommonGuiResources = Core.Gui.Properties.Resources; + +namespace Core.Gui.Attributes +{ + /// + /// Marks a method to be used to determine if a property value can be set or not. The + /// method should be public and have the signature of . + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class DynamicReadOnlyValidationMethodAttribute : Attribute + { + /// + /// Required method signature when marking a method with . + /// + /// The name of the property to be checked. + /// true if the referred property should be read-only, false if it should be editable. + public delegate bool IsPropertyReadOnly(string propertyName); + + /// + /// Creates a delegate that can be used to determine if a property should be read-only. + /// + /// The object instance declaring the validation method. + /// The delegate. + /// Thrown when there isn't a single method + /// declared on marked with + /// that is matching the signature defined by . + public static IsPropertyReadOnly CreateIsReadOnlyMethod(object target) + { + MethodInfo methodInfo = GetIsReadOnlyMethod(target); + ValidateMethodInfo(methodInfo); + return CreateIsPropertyReadOnlyDelegate(target, methodInfo); + } + + private static IsPropertyReadOnly CreateIsPropertyReadOnlyDelegate(object target, MethodInfo methodInfo) + { + return (IsPropertyReadOnly) Delegate.CreateDelegate(typeof(IsPropertyReadOnly), target, methodInfo); + } + + private static void ValidateMethodInfo(MethodInfo methodInfo) + { + if (methodInfo.ReturnType != typeof(bool)) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicReadOnlyValidationMethod_must_return_bool_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + if (parameterInfos.Length != 1) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicReadOnlyValidationMethod_incorrect_argument_count_must_be_one_string_argument_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + + if (parameterInfos[0].ParameterType != typeof(string)) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicReadOnlyValidationMethod_must_have_string_argument_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + } + + private static MethodInfo GetIsReadOnlyMethod(object obj) + { + MethodInfo[] validationMethods = obj.GetType().GetMethods() + .Where(methodInfo => IsDefined(methodInfo, typeof(DynamicReadOnlyValidationMethodAttribute))) + .ToArray(); + + if (validationMethods.Length == 0) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicReadOnlyValidationMethod_not_found_or_not_public_on_Class_0_, + obj.GetType()); + throw new MissingMethodException(message); + } + + if (validationMethods.Length > 1) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicReadOnlyValidationMethod_only_one_allowed_per_Class_0_, + obj.GetType()); + throw new MissingMethodException(message); + } + + return validationMethods[0]; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Attributes/DynamicVisibleAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Attributes/DynamicVisibleAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Attributes/DynamicVisibleAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,83 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Globalization; +using System.Reflection; +using Core.Gui.Properties; + +namespace Core.Gui.Attributes +{ + /// + /// Marks property as a conditional visible property. When this attribute is declared + /// on a property, the declaring class should have a public method marked with + /// to be used to evaluate if + /// that property should be visible or not. + /// + /// + /// + /// This attribute provides a run-time alternative to . + [AttributeUsage(AttributeTargets.Property)] + public sealed class DynamicVisibleAttribute : Attribute + { + /// + /// Determines whether the property is visible or not. + /// + /// The object. + /// The name of the property of . + /// true if the property is visible, false otherwise. + /// Thrown when + /// does not correspond to a public property of . + /// Thrown when there isn't a single method + /// declared on marked with + /// that is matching the signature defined by . + public static bool IsVisible(object value, string propertyName) + { + if (string.IsNullOrEmpty(propertyName)) + { + return BrowsableAttribute.Default.Browsable; + } + + if (!IsPropertyDynamicallyVisible(value, propertyName)) + { + return BrowsableAttribute.Default.Browsable; + } + + DynamicVisibleValidationMethodAttribute.IsPropertyVisible isPropertyVisibleDelegate = DynamicVisibleValidationMethodAttribute.CreateIsVisibleMethod(value); + + return isPropertyVisibleDelegate(propertyName); + } + + private static bool IsPropertyDynamicallyVisible(object obj, string propertyName) + { + MemberInfo propertyInfo = obj.GetType().GetProperty(propertyName); + if (propertyInfo == null) + { + throw new MissingMemberException(string.Format(CultureInfo.CurrentCulture, + Resources.Could_not_find_property_0_on_type_1_, + propertyName, obj.GetType())); + } + + return IsDefined(propertyInfo, typeof(DynamicVisibleAttribute)); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Attributes/DynamicVisibleValidationMethodAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Attributes/DynamicVisibleValidationMethodAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Attributes/DynamicVisibleValidationMethodAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,118 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Linq; +using System.Reflection; +using CoreCommonGuiResources = Core.Gui.Properties.Resources; + +namespace Core.Gui.Attributes +{ + /// + /// Marks a method to be used to determine if a property should be shown or not. The + /// method should be public and have the signature of . + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class DynamicVisibleValidationMethodAttribute : Attribute + { + /// + /// Required method signature when marking a method with . + /// + /// The name of the property to be checked. + /// true if the referred property should be visible, false if it should be hidden. + public delegate bool IsPropertyVisible(string propertyName); + + /// + /// Creates a delegate that can be used to determine if a property should be visible. + /// + /// The object instance declaring the validation method. + /// The delegate. + /// Thrown when there isn't a single method + /// declared on marked with + /// that is matching the signature defined by . + public static IsPropertyVisible CreateIsVisibleMethod(object target) + { + MethodInfo methodInfo = GetIsVisibleMethod(target); + ValidateMethodInfo(methodInfo); + return CreateIsPropertyVisibleDelegate(target, methodInfo); + } + + private static IsPropertyVisible CreateIsPropertyVisibleDelegate(object target, MethodInfo methodInfo) + { + return (IsPropertyVisible) Delegate.CreateDelegate(typeof(IsPropertyVisible), target, methodInfo); + } + + private static void ValidateMethodInfo(MethodInfo methodInfo) + { + if (methodInfo.ReturnType != typeof(bool)) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicVisibleValidationMethod_must_return_bool_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + if (parameterInfos.Length != 1) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicVisibleValidationMethod_incorrect_argument_count_must_be_one_string_argument_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + + if (parameterInfos[0].ParameterType != typeof(string)) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicVisibleValidationMethod_must_have_string_argument_on_Class_0_, + methodInfo.DeclaringType); + throw new MissingMethodException(message); + } + } + + private static MethodInfo GetIsVisibleMethod(object obj) + { + MethodInfo[] validationMethods = obj.GetType().GetMethods() + .Where(methodInfo => IsDefined(methodInfo, typeof(DynamicVisibleValidationMethodAttribute))) + .ToArray(); + + if (validationMethods.Length == 0) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicVisibleValidationMethod_not_found_or_not_public_on_Class_0_, + obj.GetType()); + throw new MissingMethodException(message); + } + + if (validationMethods.Length > 1) + { + string message = string.Format(CultureInfo.CurrentCulture, + CoreCommonGuiResources.DynamicVisibleValidationMethod_only_one_allowed_per_Class_0_, + obj.GetType()); + throw new MissingMethodException(message); + } + + return validationMethods[0]; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Attributes/PropertyOrderAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Attributes/PropertyOrderAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Attributes/PropertyOrderAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,47 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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; + +namespace Core.Gui.Attributes +{ + /// + /// Attribute that allows for controlling the order that properties appear in a property grid. + /// Ordering should occur on ascending order. + /// + [AttributeUsage(AttributeTargets.Property)] + public sealed class PropertyOrderAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// The ordering value. + public PropertyOrderAttribute(int order) + { + Order = order; + } + + /// + /// Gets the ordering value. + /// + public int Order { get; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Clipboard/ClipboardProvider.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Clipboard/ClipboardProvider.cs (revision 0) +++ Core/Gui/src/Core.Gui/Clipboard/ClipboardProvider.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,34 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Clipboard +{ + /// + /// Provides the to be used for copy/paste actions. + /// + public static class ClipboardProvider + { + /// + /// Gets the clipboard instance to be used. + /// + public static IClipboard Clipboard { get; internal set; } = new SystemClipboard(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Clipboard/IClipboard.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Clipboard/IClipboard.cs (revision 0) +++ Core/Gui/src/Core.Gui/Clipboard/IClipboard.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,54 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; + +namespace Core.Gui.Clipboard +{ + /// + /// Interface representing the clipboard. + /// + public interface IClipboard + { + /// + /// Clears the clipboard, places data on it and specifies whether the data should remain after the + /// application exits. + /// + /// The data to place on the clipboard. + /// true if the data must remain on the clipboard after the application + /// exits, false otherwise. + void SetDataObject(object data, bool copy = false); + + /// + /// Retrieves the data that is currently on the clipboard. + /// + /// The that is on the clipboard, or null if the clipboard + /// does not contain any data. + IDataObject GetDataObject(); + + /// + /// Retrieves the textual data that is currently on the clipboard. + /// + /// The textual data that is on the clipboard, or null if the clipboard does not + /// contain any textual data. + string GetText(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Clipboard/SystemClipboard.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Clipboard/SystemClipboard.cs (revision 0) +++ Core/Gui/src/Core.Gui/Clipboard/SystemClipboard.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,47 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; +using FormsClipboard = System.Windows.Forms.Clipboard; + +namespace Core.Gui.Clipboard +{ + /// + /// Implementation of based on the system . + /// + internal class SystemClipboard : IClipboard + { + public void SetDataObject(object data, bool copy = false) + { + FormsClipboard.SetDataObject(data, copy); + } + + public IDataObject GetDataObject() + { + return FormsClipboard.GetDataObject(); + } + + public string GetText() + { + return FormsClipboard.GetText(); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/ApplicationFeatureCommandHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/ApplicationFeatureCommandHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/ApplicationFeatureCommandHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,103 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.Properties; +using log4net; +using log4net.Appender; + +namespace Core.Gui.Commands +{ + /// + /// This class provides concrete implementations for . + /// + public class ApplicationFeatureCommandHandler : IApplicationFeatureCommands + { + private readonly IPropertyResolver propertyResolver; + private readonly IMainWindow mainWindow; + + /// + /// Initializes a new instance of the class. + /// + /// The object responsible for finding the object properties + /// for a given data object. + /// The main user interface of the application. + public ApplicationFeatureCommandHandler(IPropertyResolver propertyResolver, IMainWindow mainWindow) + { + this.propertyResolver = propertyResolver; + this.mainWindow = mainWindow; + } + + public void ShowPropertiesForSelection() + { + mainWindow.InitPropertiesWindowOrBringToFront(); + } + + public bool CanShowPropertiesFor(object obj) + { + return propertyResolver.GetObjectProperties(obj) != null; + } + + public void OpenLogFileExternal() + { + FileAppender fileAppender = LogManager.GetAllRepositories() + .SelectMany(r => r.GetAppenders()) + .OfType() + .FirstOrDefault(); + if (string.IsNullOrWhiteSpace(fileAppender?.File)) + { + return; + } + + TryOpenLogFileExternal(fileAppender.File); + } + + private static void TryOpenLogFileExternal(string logFile) + { + string logFolderPath = Path.GetDirectoryName(logFile); + + try + { + Process.Start(logFile); + } + catch (Exception e) + { + if (!string.IsNullOrWhiteSpace(logFolderPath) && (e is Win32Exception || e is ObjectDisposedException || e is FileNotFoundException)) + { + MessageBox.Show(Resources.ApplicationFeatureiCommandHandler_OpenLogFileExternal_Unable_to_open_log_file_Opening_log_file_directory_instead, + Resources.ApplicationFeatureCommandHandler_OpenLogFileExternal_Unable_to_open_log_file); + Process.Start(logFolderPath); + return; + } + + // Undocumented exception -> Fail Fast! + throw; + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/GuiExportHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/GuiExportHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/GuiExportHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,156 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Base.IO; +using Core.Common.Util.Reflection; +using Core.Gui.Forms; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using log4net; + +namespace Core.Gui.Commands +{ + /// + /// Class responsible for handling export workflow with user interaction. + /// + public class GuiExportHandler : IExportCommandHandler + { + private static readonly ILog log = LogManager.GetLogger(typeof(GuiExportHandler)); + + private readonly IWin32Window dialogParent; + private readonly IEnumerable exportInfos; + + /// + /// Initializes a new instance of the class. + /// + /// The parent window to show dialogs on top. + /// An enumeration of . + public GuiExportHandler(IWin32Window dialogParent, IEnumerable exportInfos) + { + this.dialogParent = dialogParent; + this.exportInfos = exportInfos; + } + + public bool CanExportFrom(object source) + { + return GetSupportedExportInfos(source).Any(); + } + + public void ExportFrom(object source) + { + ExportInfo exportInfo = GetSupportedExportInfoUsingDialog(source); + if (exportInfo == null) + { + return; + } + + ExportItem(exportInfo, source); + } + + private IEnumerable GetSupportedExportInfos(object source) + { + if (source == null) + { + return Enumerable.Empty(); + } + + Type sourceType = source.GetType(); + + return exportInfos.Where(info => (info.DataType == sourceType || sourceType.Implements(info.DataType)) && info.IsEnabled(source)); + } + + private ExportInfo GetSupportedExportInfoUsingDialog(object source) + { + ExportInfo[] supportedExportInfos = GetSupportedExportInfos(source).ToArray(); + + if (supportedExportInfos.Length == 0) + { + MessageBox.Show(Resources.GuiExportHandler_GetSupportedExporterForItemUsingDialog_No_exporter_for_this_item_available, + Resources.GuiExportHandler_GetSupportedExporterForItemUsingDialog_Error); + string itemToExportType = source == null ? "null" : source.GetType().FullName; + log.Warn(string.Format(CultureInfo.CurrentCulture, + Resources.GuiExportHandler_GetSupportedExporterForItemUsingDialog_No_exporter_for_this_item_0_available, + itemToExportType)); + return null; + } + + if (supportedExportInfos.Length == 1) + { + return supportedExportInfos[0]; + } + + using (var selectExportInfoDialog = new SelectItemDialog(dialogParent, Resources.GuiExportHandler_GetSupportedExportInfoUsingDialog_Select_exporter)) + { + foreach (ExportInfo exportInfo in supportedExportInfos) + { + selectExportInfoDialog.AddItemType(GetItemName(exportInfo), + exportInfo.Category, + exportInfo.Image, + exportInfo); + } + + if (selectExportInfoDialog.ShowDialog() == DialogResult.OK) + { + return (ExportInfo) selectExportInfoDialog.SelectedItemTag; + } + } + + return null; + } + + private static string GetItemName(ExportInfo exportInfo) + { + return exportInfo.Extension != null + ? string.Format(Resources.GetItemName_Name_0_FileExtension_1, exportInfo.Name, exportInfo.Extension) + : exportInfo.Name; + } + + private static void ExportItem(ExportInfo exportInfo, object source) + { + string exportFilePath = exportInfo.GetExportPath(); + + if (exportFilePath != null) + { + log.InfoFormat(Resources.GuiExportHandler_ExportItemUsingDialog_Start_exporting_DataType_0_, + exportInfo.Name); + + IFileExporter exporter = exportInfo.CreateFileExporter(source, exportFilePath); + + if (exporter.Export()) + { + log.InfoFormat(Resources.GuiExportHandler_ExportItemUsingDialog_Data_exported_to_File_0, exportFilePath); + log.InfoFormat(Resources.GuiExportHandler_ExportItemUsingDialog_Export_of_DataType_0_successful, + exportInfo.Name); + } + else + { + log.ErrorFormat(Resources.GuiExportHandler_ExportItemUsingDialog_Export_of_DataType_0_failed, + exportInfo.Name); + } + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/GuiImportHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/GuiImportHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/GuiImportHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,169 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Linq; +using System.Windows.Forms; +using Core.Common.Base.IO; +using Core.Common.Base.Service; +using Core.Common.Util.Reflection; +using Core.Gui.Forms; +using Core.Gui.Forms.ProgressDialog; +using Core.Gui.Helpers; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using log4net; + +namespace Core.Gui.Commands +{ + /// + /// Class responsible for handling import workflow with user interaction. + /// + public class GuiImportHandler : IImportCommandHandler + { + private static readonly ILog log = LogManager.GetLogger(typeof(GuiImportHandler)); + + private readonly IWin32Window dialogParent; + private readonly IEnumerable importInfos; + private readonly IInquiryHelper inquiryHelper; + + /// + /// Initializes a new instance of the class. + /// + /// The parent window to show dialogs on top. + /// An enumeration of . + /// Helper responsible for performing information inquiries. + /// Thrown when any input parameter is null. + public GuiImportHandler(IWin32Window dialogParent, IEnumerable importInfos, IInquiryHelper inquiryHelper) + { + if (dialogParent == null) + { + throw new ArgumentNullException(nameof(dialogParent)); + } + + if (importInfos == null) + { + throw new ArgumentNullException(nameof(importInfos)); + } + + if (inquiryHelper == null) + { + throw new ArgumentNullException(nameof(inquiryHelper)); + } + + this.dialogParent = dialogParent; + this.importInfos = importInfos; + this.inquiryHelper = inquiryHelper; + } + + public IEnumerable GetSupportedImportInfos(object target) + { + if (target == null) + { + return Enumerable.Empty(); + } + + Type targetType = target.GetType(); + + return importInfos.Where(info => (info.DataType == targetType || targetType.Implements(info.DataType)) + && (info.IsEnabled == null || info.IsEnabled(target))); + } + + public void ImportOn(object target, IEnumerable supportedImportInfos) + { + ImportInfo importInfo = SelectImportInfo(target, supportedImportInfos.ToArray()); + + if (importInfo == null) + { + return; + } + + ImportItemsUsingDialog(importInfo, target); + } + + private ImportInfo SelectImportInfo(object target, IReadOnlyList supportedImportInfos) + { + if (supportedImportInfos.Count == 0) + { + MessageBox.Show(Resources.GuiImportHandler_SelectImportInfo_No_importer_available_for_this_item, + Resources.GuiImportHandler_SelectImportInfo_Error); + log.ErrorFormat(Resources.GuiImportHandler_SelectImportInfo_No_importer_available_for_this_item_0_, + target); + return null; + } + + if (supportedImportInfos.Count == 1) + { + return supportedImportInfos[0]; + } + + using (var selectImporterDialog = new SelectItemDialog(dialogParent, Resources.GuiImportHandler_GetSupportedImporterUsingDialog_Select_importer)) + { + foreach (ImportInfo importInfo in supportedImportInfos) + { + selectImporterDialog.AddItemType(GetItemName(importInfo), + importInfo.Category, + importInfo.Image, + importInfo); + } + + if (selectImporterDialog.ShowDialog() == DialogResult.OK) + { + return (ImportInfo) selectImporterDialog.SelectedItemTag; + } + } + + return null; + } + + private static string GetItemName(ImportInfo importInfo) + { + return importInfo.FileFilterGenerator != null + ? string.Format(Resources.GetItemName_Name_0_FileExtension_1, importInfo.Name, importInfo.FileFilterGenerator.Extension) + : importInfo.Name; + } + + private void ImportItemsUsingDialog(ImportInfo importInfo, object target) + { + string fileDialogResult = inquiryHelper.GetSourceFileLocation(importInfo.FileFilterGenerator.Filter); + + if (fileDialogResult != null && importInfo.VerifyUpdates(target)) + { + RunImportActivity(importInfo.CreateFileImporter(target, fileDialogResult), importInfo.Name); + } + else + { + log.InfoFormat(Resources.GuiImportHandler_ImportItemsUsingDialog_Importing_cancelled); + } + } + + private void RunImportActivity(IFileImporter importer, string importName) + { + var activity = new FileImportActivity(importer, + !string.IsNullOrEmpty(importName) + ? string.Format(Resources.GuiImportHandler_RunImportActivity_Importing_0_, importName) + : string.Empty); + + ActivityProgressDialogRunner.Run(dialogParent, activity); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/GuiUpdateHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/GuiUpdateHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/GuiUpdateHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,175 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.IO; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Base.IO; +using Core.Common.Base.Service; +using Core.Common.Util.Reflection; +using Core.Gui.Forms; +using Core.Gui.Forms.ProgressDialog; +using Core.Gui.Helpers; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using log4net; + +namespace Core.Gui.Commands +{ + /// + /// Class responsible for handling update workflow with user interaction. + /// + public class GuiUpdateHandler : IUpdateCommandHandler + { + private static readonly ILog log = LogManager.GetLogger(typeof(GuiUpdateHandler)); + + private readonly IWin32Window dialogParent; + private readonly IEnumerable updateInfos; + private readonly IInquiryHelper inquiryHelper; + + /// + /// Initializes a new instance of the class. + /// + /// The parent window to show dialogs on top. + /// An enumeration of . + /// Helper responsible for performing information inquiries. + /// Thrown when any input parameter is null. + public GuiUpdateHandler(IWin32Window dialogParent, IEnumerable updateInfos, IInquiryHelper inquiryHelper) + { + if (dialogParent == null) + { + throw new ArgumentNullException(nameof(dialogParent)); + } + + if (updateInfos == null) + { + throw new ArgumentNullException(nameof(updateInfos)); + } + + if (inquiryHelper == null) + { + throw new ArgumentNullException(nameof(inquiryHelper)); + } + + this.dialogParent = dialogParent; + this.updateInfos = updateInfos; + this.inquiryHelper = inquiryHelper; + } + + public bool CanUpdateOn(object target) + { + return GetSupportedUpdateInfos(target).Any(); + } + + public void UpdateOn(object target) + { + UpdateInfo updateInfo = GetSupportedUpdaterUsingDialog(target); + if (updateInfo != null) + { + UpdateItemsUsingDialog(updateInfo, target); + } + } + + private IEnumerable GetSupportedUpdateInfos(object target) + { + if (target == null) + { + return Enumerable.Empty(); + } + + Type targetType = target.GetType(); + + return updateInfos.Where(info => (info.DataType == targetType || targetType.Implements(info.DataType)) && info.IsEnabled(target)); + } + + private UpdateInfo GetSupportedUpdaterUsingDialog(object target) + { + UpdateInfo[] supportedUpdateInfo = GetSupportedUpdateInfos(target).ToArray(); + if (supportedUpdateInfo.Length == 0) + { + MessageBox.Show(dialogParent, + Resources.GuiUpdateHandler_GetSupportedUpdaterForTargetType_No_updater_available_for_this_item, + Resources.GuiUpdateHandler_GetSupportedUpdaterForTargetType_Error); + log.ErrorFormat(Resources.GuiUpdateHandler_GetSupportedUpdaterForTargetType_No_updater_available_for_this_item_0_, + target); + return null; + } + + if (supportedUpdateInfo.Length == 1) + { + return supportedUpdateInfo[0]; + } + + using (var selectUpdaterDialog = new SelectItemDialog(dialogParent, Resources.GuiUpdateHandler_GetSupportedUpdaterUsingDialog_Select_updater)) + { + foreach (UpdateInfo updateInfo in supportedUpdateInfo) + { + selectUpdaterDialog.AddItemType(updateInfo.Name, updateInfo.Category, updateInfo.Image, null); + } + + if (selectUpdaterDialog.ShowDialog() == DialogResult.OK) + { + return supportedUpdateInfo.First(i => i.Name == selectUpdaterDialog.SelectedItemTypeName); + } + } + + return null; + } + + private void UpdateItemsUsingDialog(UpdateInfo updateInfo, object target) + { + string oldPath = updateInfo.CurrentPath(target); + string filePath = oldPath; + if (!File.Exists(filePath)) + { + filePath = inquiryHelper.GetSourceFileLocation(updateInfo.FileFilterGenerator.Filter); + } + + if (filePath != null && updateInfo.VerifyUpdates(target)) + { + RunUpdateActivity(updateInfo.CreateFileImporter(target, filePath), updateInfo.Name); + } + else + { + if (!string.IsNullOrEmpty(oldPath)) + { + log.InfoFormat(Resources.GuiUpdateHandler_UpdateItemsUsingDialog_Updating_from_Path_0_cancelled, oldPath); + } + else + { + log.InfoFormat(Resources.GuiUpdateHandler_UpdateItemsUsingDialog_Updating_cancelled); + } + } + } + + private void RunUpdateActivity(IFileImporter importer, string updateName) + { + var activity = new FileImportActivity(importer, + !string.IsNullOrEmpty(updateName) + ? string.Format(Resources.GuiUpdateHandler_RunUpdateActivity_Updating_0_, updateName) + : string.Empty); + + ActivityProgressDialogRunner.Run(dialogParent, activity); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/IApplicationFeatureCommands.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/IApplicationFeatureCommands.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/IApplicationFeatureCommands.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Commands +{ + /// + /// Interface that declares application feature manipulation. + /// + public interface IApplicationFeatureCommands + { + /// + /// Makes the properties window visible for the given object and selects it. + /// + void ShowPropertiesForSelection(); + + /// + /// Indicates if there is a property-edit window defined for some object. + /// + /// The object to check. + /// true if a property view is defined, false otherwise. + bool CanShowPropertiesFor(object obj); + + /// + /// Opens the current log-file, or the folder with logs if no current log-file is available. + /// + void OpenLogFileExternal(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/ICommandsOwner.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/ICommandsOwner.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/ICommandsOwner.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,44 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Commands +{ + /// + /// Object that holds the commands available within the application. + /// + public interface ICommandsOwner + { + /// + /// Gets the commands related to application features. + /// + IApplicationFeatureCommands ApplicationCommands { get; } + + /// + /// Gets the commands related to persistency. + /// + IStorageCommands StorageCommands { get; } + + /// + /// Gets the commands related to view manipulation. + /// + IViewCommands ViewCommands { get; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/IExportCommandHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/IExportCommandHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/IExportCommandHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,48 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Commands +{ + /// + /// Interface declaring commands/methods related to exporting data. + /// + public interface IExportCommandHandler + { + /// + /// Indicates if there are exporters for the given source object. + /// + /// The source object to check exporter availability for. + /// true if there are exporters available, false otherwise. + bool CanExportFrom(object source); + + /// + /// Perform the export workflow by the following steps: + /// + /// If multiple exporters are available for the source object, determine + /// which exporter to use; + /// Create the exporter; + /// Use the exporter to export from the source object. + /// + /// + /// The data object to export from. + void ExportFrom(object source); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/IImportCommandHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/IImportCommandHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/IImportCommandHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,54 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Collections.Generic; +using Core.Gui.Plugin; + +namespace Core.Gui.Commands +{ + /// + /// Interface declaring commands/methods related to importing data. + /// + public interface IImportCommandHandler + { + /// + /// Gets all supported instances for the provided . + /// + /// The data object to get the supported instances for. + /// An enumeration of instances. + IEnumerable GetSupportedImportInfos(object target); + + /// + /// Perform the import workflow by the following steps: + /// + /// If multiple importers are available for the target object, determine + /// which importer to use; + /// Create the importer; + /// Obtain data from the importer; + /// Set the imported data on the target object. + /// + /// + /// The data object to import to. + /// The instances representing the importers available + /// for the target object. + void ImportOn(object target, IEnumerable supportedImportInfos); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/IStorageCommands.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/IStorageCommands.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/IStorageCommands.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,84 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Base.Data; +using Core.Common.Base.IO; +using Core.Common.Base.Storage; + +namespace Core.Gui.Commands +{ + /// + /// Interface for exposing commands/methods related to saving/loading a . + /// + public interface IStorageCommands + { + /// + /// Closes the current project and creates a new one. + /// + void CreateNewProject(); + + /// + /// Checks whether the current project has unsaved changes. If so, these unsaved changes + /// will be handled. + /// + /// true if there were no unsaved changes or when the changes were + /// successfully handled, false if the unsaved changes were not handled. + bool HandleUnsavedChanges(); + + /// + /// Asks the user for a file-location to save the current project, then proceeds + /// to persist the data to that location. + /// + /// Returns true if the save was successful, false otherwise. + bool SaveProjectAs(); + + /// + /// Saves the current project to the defined file, or asks the user for a location + /// if one hasn't been defined yet. + /// + /// Returns true if the save was successful, false otherwise. + bool SaveProject(); + + /// + /// Asks the user to select the file to load a project from, then returns the selected + /// file path of the selected file. + /// + /// The file path of the selected file. + string GetExistingProjectFilePath(); + + /// + /// Loads a project from a given file-location. + /// + /// Location of the storage file. + /// true if an existing has been loaded, + /// false otherwise. + /// Thrown when is + /// not a valid file path. + /// Thrown when + /// is null. + /// Thrown when the file at + /// couldn't be read. + /// Thrown when the file at + /// is not a valid project file. + bool OpenExistingProject(string filePath); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/IUpdateCommandHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/IUpdateCommandHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/IUpdateCommandHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,49 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Commands +{ + /// + /// Interface declaring commands/methods related to updating data. + /// + public interface IUpdateCommandHandler + { + /// + /// Indicates if there are updaters for the given target object. + /// + /// The target object to check updater availability for. + /// true if there are updaters available, false otherwise. + bool CanUpdateOn(object target); + + /// + /// Perform the update workflow by the following steps: + /// + /// If multiple updaters are available for the target object, determine + /// which updater to use; + /// Create the updater; + /// Obtain the data from the updater; + /// Update the data on the target object. + /// + /// + /// The data object to update. + void UpdateOn(object target); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/IViewCommands.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/IViewCommands.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/IViewCommands.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,57 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Commands +{ + /// + /// Interface declaring methods related to manipulating views within the application. + /// + public interface IViewCommands + { + /// + /// Open the view for the application's selection. + /// + /// If multiple views are available, the user is asked which view to use. + /// + void OpenViewForSelection(); + + /// + /// Open the view for the given data object. + /// + /// The data object for which a view must be opened. + /// If multiple views are available, the user is asked which view to use. + /// + void OpenView(object viewData); + + /// + /// Removes all views that are associated to the given data object and/or its children. + /// + /// The root data object for which all views must be closed. + void RemoveAllViewsForItem(object viewData); + + /// + /// Indicates if a there are any views available for the application's selection. + /// + /// The data object to open views for. + /// true if there are any views for , false otherwise. + bool CanOpenViewFor(object viewData); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/StorageCommandHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/StorageCommandHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/StorageCommandHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,316 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.IO; +using System.Windows.Forms; +using Core.Common.Base.Data; +using Core.Common.Base.IO; +using Core.Common.Base.Service; +using Core.Common.Base.Storage; +using Core.Gui.Forms.ProgressDialog; +using Core.Gui.Helpers; +using Core.Gui.Properties; +using log4net; + +namespace Core.Gui.Commands +{ + /// + /// Class responsible for persistency of . + /// + public class StorageCommandHandler : IStorageCommands + { + private static readonly ILog log = LogManager.GetLogger(typeof(StorageCommandHandler)); + + private readonly IWin32Window dialogParent; + private readonly IProjectOwner projectOwner; + private readonly IStoreProject projectPersister; + private readonly IProjectFactory projectFactory; + private readonly IMigrateProject projectMigrator; + private readonly IInquiryHelper inquiryHelper; + + /// + /// Initializes a new instance of the class. + /// + /// Class responsible to storing and loading the application project. + /// Class responsible for the migration of the application projects. + /// The factory to use when creating new projects. + /// The class owning the application project. + /// The object facilitating user interaction. + /// Controller for UI. + public StorageCommandHandler(IStoreProject projectStorage, IMigrateProject projectMigrator, + IProjectFactory projectFactory, IProjectOwner projectOwner, + IInquiryHelper inquiryHelper, IWin32Window dialogParent) + { + this.dialogParent = dialogParent; + this.projectOwner = projectOwner; + this.inquiryHelper = inquiryHelper; + projectPersister = projectStorage; + this.projectMigrator = projectMigrator; + this.projectFactory = projectFactory; + } + + public bool HandleUnsavedChanges() + { + if (IsCurrentNew()) + { + return true; + } + + IProject project = projectOwner.Project; + projectPersister.StageProject(project); + try + { + if (!projectPersister.HasStagedProjectChanges(projectOwner.ProjectFilePath)) + { + projectPersister.UnstageProject(); + return true; + } + } + catch (StorageException e) + { + log.Error(e.Message, e); + projectPersister.UnstageProject(); + } + + bool unsavedChangesHandled = ShowSaveUnsavedChangesDialog(); + + if (projectPersister.HasStagedProject) + { + projectPersister.UnstageProject(); + } + + return unsavedChangesHandled; + } + + public void CreateNewProject() + { + if (!HandleUnsavedChanges()) + { + log.Info(Resources.StorageCommandHandler_NewProject_Creating_new_project_canceled); + return; + } + + log.Info(Resources.Creating_new_project_started); + projectOwner.SetProject(projectFactory.CreateNewProject(), null); + log.Info(Resources.Creating_new_project_successful); + } + + public string GetExistingProjectFilePath() + { + using (var openFileDialog = new OpenFileDialog + { + Filter = projectPersister.OpenProjectFileFilter, + Title = Resources.OpenFileDialog_Title + }) + { + if (openFileDialog.ShowDialog(dialogParent) != DialogResult.Cancel && HandleUnsavedChanges()) + { + return openFileDialog.FileName; + } + } + + return null; + } + + public bool OpenExistingProject(string filePath) + { + try + { + return OpenExistingProjectCore(filePath); + } + catch (Exception e) when (e is ArgumentException || e is CriticalFileReadException || e is StorageValidationException) + { + log.Error(e.Message, e); + projectOwner.SetProject(projectFactory.CreateNewProject(), null); + return false; + } + } + + public bool SaveProjectAs() + { + IProject project = projectOwner.Project; + string filePath = OpenProjectSaveFileDialog(project.Name); + + if (string.IsNullOrWhiteSpace(filePath)) + { + return false; + } + + var activity = new SaveProjectActivity(project, filePath, false, projectPersister, projectOwner); + ActivityProgressDialogRunner.Run(dialogParent, activity); + return activity.State == ActivityState.Finished; + } + + public bool SaveProject() + { + IProject project = projectOwner.Project; + string filePath = projectOwner.ProjectFilePath; + + // If file path is not set, go to SaveAs + if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath)) + { + return SaveProjectAs(); + } + + var activity = new SaveProjectActivity(project, filePath, true, projectPersister, projectOwner); + ActivityProgressDialogRunner.Run(dialogParent, activity); + return activity.State == ActivityState.Finished; + } + + /// + /// Opens the given project file and determines if migration to the current version is + /// required and performs migration if needed. + /// + /// The project file to open. + /// Returns true if the project was successfully opened; Returns + /// false if an error occurred or when opening the project has been cancelled. + /// Thrown when is + /// not a valid file path. + /// Thrown when + /// is null. + /// Thrown when the file at + /// couldn't be read. + /// Thrown when the file at + /// is not a valid project file. + private bool OpenExistingProjectCore(string filePath) + { + OpenProjectActivity.ProjectMigrationConstructionProperties migrationProperties; + if (PrepareProjectMigration(filePath, out migrationProperties) == MigrationRequired.Aborted) + { + return false; + } + + return MigrateAndOpenProject(filePath, migrationProperties); + } + + /// + /// Check if migration is required and if so the migration settings are initialized. + /// + /// The project file to open. + /// Output: Will be null if this method + /// returns or . + /// Will be a concrete instance if this method returns . + /// Indicates if migration is required or not, or that the operation has + /// been cancelled. + /// Thrown when is + /// not a valid file path. + /// Thrown when + /// is null. + /// Thrown when the file at + /// couldn't be read. + /// Thrown when the file at + /// is not a valid project file. + private MigrationRequired PrepareProjectMigration(string filePath, + out OpenProjectActivity.ProjectMigrationConstructionProperties migrationConstructionProperties) + { + migrationConstructionProperties = null; + MigrationRequired migrationNeeded = projectMigrator.ShouldMigrate(filePath); + if (migrationNeeded == MigrationRequired.Yes) + { + string projectFilePathTakingIntoAccountMigration = projectMigrator.DetermineMigrationLocation(filePath); + if (string.IsNullOrWhiteSpace(projectFilePathTakingIntoAccountMigration)) + { + migrationNeeded = MigrationRequired.Aborted; + } + else + { + migrationConstructionProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + Migrator = projectMigrator, + MigrationFilePath = projectFilePathTakingIntoAccountMigration + }; + } + } + + return migrationNeeded; + } + + /// + /// Starts an activity that can migrate the project if required, then opens the project. + /// + /// The project file to open. + /// The construction properties related to migrating + /// a project. Can be null. + /// Returns true if the operation completed successfully; Returns + /// false otherwise (for example when the operation failed or was cancelled). + /// Thrown when is + /// not a valid file path. + /// Thrown when + /// is null. + private bool MigrateAndOpenProject(string filePath, OpenProjectActivity.ProjectMigrationConstructionProperties migrationProperties) + { + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = filePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectPersister + }; + var activity = new OpenProjectActivity(openProjectProperties, migrationProperties); + ActivityProgressDialogRunner.Run(dialogParent, activity); + + return activity.State == ActivityState.Finished; + } + + private bool IsCurrentNew() + { + return projectOwner.Project.Equals(projectFactory.CreateNewProject()); + } + + private bool ShowSaveUnsavedChangesDialog() + { + string inquiry = string.Format(CultureInfo.CurrentCulture, + Resources.StorageCommandHandler_OpenSaveOrDiscardProjectDialog_SaveChangesToProject_0, + projectOwner.Project.Name); + OptionalStepResult confirmation = inquiryHelper.InquirePerformOptionalStep(Resources.StorageCommandHandler_ClosingProject_Title, + inquiry); + + switch (confirmation) + { + case OptionalStepResult.Cancel: + return false; + case OptionalStepResult.PerformOptionalStep: + ReleaseDatabaseFileHandle(); + return SaveProject(); + } + + return true; + } + + private static void ReleaseDatabaseFileHandle() + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + /// + /// Prompts a new to select a location for saving the project file. + /// + /// A string containing the file name selected in the file dialog box. + /// The selected project file, or null otherwise. + private string OpenProjectSaveFileDialog(string projectName) + { + return inquiryHelper.GetTargetFileLocation(projectPersister.SaveProjectFileFilter, projectName); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Commands/ViewCommandHandler.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Commands/ViewCommandHandler.cs (revision 0) +++ Core/Gui/src/Core.Gui/Commands/ViewCommandHandler.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,86 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Collections.Generic; +using System.Linq; +using Core.Gui.Selection; + +namespace Core.Gui.Commands +{ + /// + /// This class provides concrete implementations for . + /// + public class ViewCommandHandler : IViewCommands + { + private readonly IViewController viewController; + private readonly IApplicationSelection applicationSelection; + private readonly IPluginsHost pluginsHost; + + /// + /// Initializes a new instance of the class. + /// + /// The controller for views. + /// The application selection mechanism. + /// The plugins host. + public ViewCommandHandler(IViewController viewController, IApplicationSelection applicationSelection, + IPluginsHost pluginsHost) + { + this.viewController = viewController; + this.applicationSelection = applicationSelection; + this.pluginsHost = pluginsHost; + } + + public void OpenViewForSelection() + { + OpenView(applicationSelection.Selection); + } + + public bool CanOpenViewFor(object viewData) + { + return viewController.DocumentViewController.GetViewInfosFor(viewData).Any(); + } + + public void OpenView(object viewData) + { + viewController.DocumentViewController.OpenViewForData(viewData); + } + + public void RemoveAllViewsForItem(object viewData) + { + if (viewData == null || viewController.ViewHost == null) + { + return; + } + + var objectsToRemoveViewsFor = new List + { + viewData + }; + + objectsToRemoveViewsFor.AddRange(pluginsHost.GetAllDataWithViewDefinitionsRecursively(viewData).Cast()); + + foreach (object data in objectsToRemoveViewsFor) + { + viewController.DocumentViewController.CloseAllViewsFor(data); + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ContextMenu/ContextMenuBuilder.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ContextMenu/ContextMenuBuilder.cs (revision 0) +++ Core/Gui/src/Core.Gui/ContextMenu/ContextMenuBuilder.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,199 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Drawing; +using System.Windows.Forms; +using Core.Common.Controls.TreeView; +using Core.Gui.Commands; +using Core.Gui.Plugin; +using Core.Gui.Properties; + +namespace Core.Gui.ContextMenu +{ + /// + /// This class represents a builder which can be used to create a context menu, which's items require information + /// on the in order to render or perform actions. + /// + public class ContextMenuBuilder : IContextMenuBuilder + { + private readonly GuiContextMenuItemFactory guiItemsFactory; + private readonly TreeViewContextMenuItemFactory treeViewItemsFactory; + private readonly ContextMenuStrip contextMenu; + + /// + /// Creates a new instance of . + /// + /// The from which to obtain + /// information to render and bind actions to the items of the . + /// The from which to obtain + /// information to render and bind actions to the items of the . + /// The from which to obtain + /// information to render and bind actions to the items of the . + /// The from which to obtain + /// information to render and bind actions to the items of the . + /// The from which to obtain information to render + /// and bind actions to the items of the . + /// The data object for which to create a . + /// The to use while executing the actions. + /// Thrown when any input argument is null. + public ContextMenuBuilder(IApplicationFeatureCommands featureCommandHandler, + IImportCommandHandler importCommandHandler, + IExportCommandHandler exportCommandHandler, + IUpdateCommandHandler updateCommandHandler, + IViewCommands viewCommands, object dataValue, + TreeViewControl treeViewControl) + { + try + { + guiItemsFactory = new GuiContextMenuItemFactory(featureCommandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + dataValue); + + treeViewItemsFactory = new TreeViewContextMenuItemFactory(dataValue, treeViewControl); + } + catch (ArgumentNullException e) + { + throw new ContextMenuBuilderException(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, e); + } + + contextMenu = new ContextMenuStrip(); + } + + public IContextMenuBuilder AddRenameItem() + { + AddItem(treeViewItemsFactory.CreateRenameItem()); + return this; + } + + public IContextMenuBuilder AddDeleteItem() + { + AddItem(treeViewItemsFactory.CreateDeleteItem()); + return this; + } + + public IContextMenuBuilder AddDeleteChildrenItem() + { + AddItem(treeViewItemsFactory.CreateDeleteChildrenItem()); + return this; + } + + public IContextMenuBuilder AddExpandAllItem() + { + AddItem(treeViewItemsFactory.CreateExpandAllItem()); + return this; + } + + public IContextMenuBuilder AddCollapseAllItem() + { + AddItem(treeViewItemsFactory.CreateCollapseAllItem()); + return this; + } + + public IContextMenuBuilder AddOpenItem() + { + AddItem(guiItemsFactory.CreateOpenItem()); + return this; + } + + public IContextMenuBuilder AddExportItem() + { + AddItem(guiItemsFactory.CreateExportItem()); + return this; + } + + public IContextMenuBuilder AddImportItem(IEnumerable importInfos = null) + { + AddItem(guiItemsFactory.CreateImportItem(importInfos)); + return this; + } + + public IContextMenuBuilder AddImportItem(string text, string toolTip, Image image, IEnumerable importInfos = null) + { + AddItem(guiItemsFactory.CreateImportItem(text, toolTip, image, importInfos)); + return this; + } + + public IContextMenuBuilder AddUpdateItem() + { + AddItem(guiItemsFactory.CreateUpdateItem()); + return this; + } + + public IContextMenuBuilder AddPropertiesItem() + { + AddItem(guiItemsFactory.CreatePropertiesItem()); + return this; + } + + public IContextMenuBuilder AddSeparator() + { + if (MayAddSeparator()) + { + AddItem(new ToolStripSeparator()); + } + + return this; + } + + public IContextMenuBuilder AddCustomItem(StrictContextMenuItem item) + { + AddItem(item); + return this; + } + + public ContextMenuStrip Build() + { + if (contextMenu.Items.Count > 0) + { + int lastIndex = contextMenu.Items.Count - 1; + if (contextMenu.Items[lastIndex] is ToolStripSeparator) + { + contextMenu.Items.RemoveAt(lastIndex); + } + } + + return contextMenu; + } + + private bool MayAddSeparator() + { + if (contextMenu.Items.Count == 0) + { + return false; + } + + return !(contextMenu.Items[contextMenu.Items.Count - 1] is ToolStripSeparator); + } + + private void AddItem(ToolStripItem item) + { + if (item != null) + { + contextMenu.Items.Add(item); + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ContextMenu/ContextMenuBuilderException.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ContextMenu/ContextMenuBuilderException.cs (revision 0) +++ Core/Gui/src/Core.Gui/ContextMenu/ContextMenuBuilderException.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,68 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Runtime.Serialization; + +namespace Core.Gui.ContextMenu +{ + /// + /// Exception thrown when something went wrong while initializing a . + /// + [Serializable] + public class ContextMenuBuilderException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public ContextMenuBuilderException() {} + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The message that describes the error. + public ContextMenuBuilderException(string message) + : base(message) {} + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, + /// or null if no inner exception is specified. + public ContextMenuBuilderException(string message, Exception inner) : base(message, inner) {} + + /// + /// Initializes a new instance of with + /// serialized data. + /// The that holds the serialized + /// object data about the exception being thrown. + /// The that contains contextual + /// information about the source or destination. + /// The parameter is + /// null. + /// The class name is null or + /// is zero (0). + protected ContextMenuBuilderException(SerializationInfo info, StreamingContext context) : base(info, context) {} + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ContextMenu/GuiContextMenuItemFactory.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ContextMenu/GuiContextMenuItemFactory.cs (revision 0) +++ Core/Gui/src/Core.Gui/ContextMenu/GuiContextMenuItemFactory.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,251 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Drawing; +using System.Linq; +using System.Windows.Forms; +using Core.Gui.Commands; +using Core.Gui.Plugin; +using Core.Gui.Properties; + +namespace Core.Gui.ContextMenu +{ + /// + /// This class represents a factory for creating . + /// + internal class GuiContextMenuItemFactory + { + private readonly IApplicationFeatureCommands applicationFeatureCommandHandler; + private readonly IImportCommandHandler importCommandHandler; + private readonly IExportCommandHandler exportCommandHandler; + private readonly IUpdateCommandHandler updateCommandHandler; + private readonly IViewCommands viewCommands; + private readonly object dataObject; + + /// + /// Creates a new instance of . + /// + /// The + /// which contains information for creating the . + /// The which contains + /// information for creating the . + /// The which contains + /// information for creating the . + /// The which contains + /// information for creating the . + /// The which contains information for + /// creating the . + /// The data object for which to create . + /// Thrown when any input argument is null. + public GuiContextMenuItemFactory(IApplicationFeatureCommands applicationFeatureCommandHandler, + IImportCommandHandler importCommandHandler, + IExportCommandHandler exportCommandHandler, + IUpdateCommandHandler updateCommandHandler, + IViewCommands viewCommandsHandler, + object dataObject) + { + if (applicationFeatureCommandHandler == null) + { + throw new ArgumentNullException(nameof(applicationFeatureCommandHandler), + Resources.GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_gui); + } + + if (importCommandHandler == null) + { + throw new ArgumentNullException(nameof(importCommandHandler), + Resources.GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_import_handler); + } + + if (exportCommandHandler == null) + { + throw new ArgumentNullException(nameof(exportCommandHandler), + Resources.GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_export_handler); + } + + if (updateCommandHandler == null) + { + throw new ArgumentNullException(nameof(updateCommandHandler), + Resources.GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_update_handler); + } + + if (viewCommandsHandler == null) + { + throw new ArgumentNullException(nameof(viewCommandsHandler), + Resources.GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_view_commands); + } + + if (dataObject == null) + { + throw new ArgumentNullException(nameof(dataObject), + Resources.ContextMenuItemFactory_Can_not_create_context_menu_items_without_data); + } + + this.applicationFeatureCommandHandler = applicationFeatureCommandHandler; + this.importCommandHandler = importCommandHandler; + this.exportCommandHandler = exportCommandHandler; + this.updateCommandHandler = updateCommandHandler; + viewCommands = viewCommandsHandler; + this.dataObject = dataObject; + } + + /// + /// Creates a which is bound to the action of opening a view + /// for the data of the . + /// + /// The created . + public ToolStripItem CreateOpenItem() + { + bool canOpenView = viewCommands.CanOpenViewFor(dataObject); + var newItem = new ToolStripMenuItem(Resources.Open) + { + ToolTipText = Resources.Open_ToolTip, + Image = Resources.OpenIcon, + Enabled = canOpenView + }; + newItem.Click += (s, e) => viewCommands.OpenView(dataObject); + + return newItem; + } + + /// + /// Creates a which is bound to the action of exporting + /// the data of the . + /// + /// The created . + public ToolStripItem CreateExportItem() + { + bool canExport = exportCommandHandler.CanExportFrom(dataObject); + var newItem = new ToolStripMenuItem(Resources.Export) + { + ToolTipText = Resources.Export_ToolTip, + Image = Resources.ExportIcon, + Enabled = canExport + }; + newItem.Click += (s, e) => exportCommandHandler.ExportFrom(dataObject); + + return newItem; + } + + /// + /// Creates a which is bound to the action of importing + /// to the data of the given . + /// + /// An enumeration of instances, + /// representing one or more supported import actions. + /// The created . + /// When no parameter is provided, the supported + /// instances - as registered by the plugins - will be resolved + /// dynamically. + public ToolStripItem CreateImportItem(IEnumerable importInfos = null) + { + return CreateImportItem(Resources.Import, Resources.Import_ToolTip, Resources.ImportIcon, importInfos); + } + + /// + /// Creates a which is bound to the action of importing + /// to the data of the given . + /// + /// The text of the import item. + /// The toolTip of the import item. + /// The image of the import item. + /// An enumeration of instances, + /// representing one or more supported import actions. + /// The created . + /// Thrown when + /// is null or only whitespace. + /// Thrown when + /// or is null. + /// When no parameter is provided, the supported + /// instances - as registered by the plugins - will be resolved + /// dynamically. + public ToolStripItem CreateImportItem(string text, string toolTip, Image image, IEnumerable importInfos = null) + { + if (string.IsNullOrWhiteSpace(text)) + { + throw new ArgumentException(@"Text should be set.", nameof(text)); + } + + if (toolTip == null) + { + throw new ArgumentNullException(nameof(toolTip)); + } + + if (image == null) + { + throw new ArgumentNullException(nameof(image)); + } + + importInfos = importInfos?.Where(info => info.IsEnabled == null || info.IsEnabled(dataObject)).ToArray() + ?? importCommandHandler.GetSupportedImportInfos(dataObject); + + var importItem = new ToolStripMenuItem(text) + { + ToolTipText = toolTip, + Image = image, + Enabled = importInfos.Any() + }; + + importItem.Click += (s, e) => importCommandHandler.ImportOn(dataObject, importInfos); + + return importItem; + } + + /// + /// Creates a which is bound to the action of updating + /// the data of the given . + /// + /// The created . + public ToolStripItem CreateUpdateItem() + { + bool canUpdate = updateCommandHandler.CanUpdateOn(dataObject); + var newItem = new ToolStripMenuItem(Resources.Update) + { + ToolTipText = Resources.Update_ToolTip, + Image = Resources.RefreshIcon, + Enabled = canUpdate + }; + newItem.Click += (s, e) => updateCommandHandler.UpdateOn(dataObject); + + return newItem; + } + + /// + /// Creates a which is bound to the action of showing + /// the properties of the data of the given . + /// + /// The created . + public ToolStripItem CreatePropertiesItem() + { + bool canShowProperties = applicationFeatureCommandHandler.CanShowPropertiesFor(dataObject); + var newItem = new ToolStripMenuItem(Resources.Properties) + { + ToolTipText = Resources.Properties_ToolTip, + Image = Resources.PropertiesHS, + Enabled = canShowProperties + }; + newItem.Click += (s, e) => applicationFeatureCommandHandler.ShowPropertiesForSelection(); + + return newItem; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ContextMenu/IContextMenuBuilder.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ContextMenu/IContextMenuBuilder.cs (revision 0) +++ Core/Gui/src/Core.Gui/ContextMenu/IContextMenuBuilder.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,138 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Drawing; +using System.Windows.Forms; +using Core.Gui.Plugin; + +namespace Core.Gui.ContextMenu +{ + /// + /// Specifies the interface for objects that build context menus. + /// + public interface IContextMenuBuilder + { + /// + /// Adds an item to the , which starts edit mode for the name of . + /// + /// The itself. + IContextMenuBuilder AddRenameItem(); + + /// + /// Adds an item to the , which deletes the . + /// + /// The itself. + IContextMenuBuilder AddDeleteItem(); + + /// + /// Adds an item to the , which deletes the children + /// of . + /// + /// The itself. + IContextMenuBuilder AddDeleteChildrenItem(); + + /// + /// Adds an item to the , which expands the . + /// + /// The itself. + IContextMenuBuilder AddExpandAllItem(); + + /// + /// Adds an item to the , which collapses the . + /// + /// The itself. + IContextMenuBuilder AddCollapseAllItem(); + + /// + /// Adds an item to the , which opens a view for the data of the . + /// + /// The itself. + IContextMenuBuilder AddOpenItem(); + + /// + /// Adds an item to the , which exports the data of the . + /// + /// The itself. + IContextMenuBuilder AddExportItem(); + + /// + /// Adds an item to the , which imports to the data of the . + /// + /// An enumeration of instances, representing one or more + /// supported import actions. + /// The itself. + /// When no parameter is provided, the supported + /// instances - as registered by the plugins - will be resolved dynamically. + IContextMenuBuilder AddImportItem(IEnumerable importInfos = null); + + /// + /// Adds an item to the , which imports to the data of the . + /// + /// The text of the import item. + /// The tooltip of the import item. + /// The image of the import item. + /// An enumeration of instances, representing one or more + /// supported import actions. + /// The itself. + /// Thrown when is null or only whitespace. + /// Thrown when or + /// is null. + /// When no parameter is provided, the supported + /// instances - as registered by the plugins - will be resolved dynamically. + IContextMenuBuilder AddImportItem(string text, string toolTip, Image image, IEnumerable importInfos = null); + + /// + /// Adds an item to the , which updates the data of the . + /// + /// The itself. + IContextMenuBuilder AddUpdateItem(); + + /// + /// Adds an item to the , which shows properties of the data of the . + /// + /// The itself. + IContextMenuBuilder AddPropertiesItem(); + + /// + /// Adds a to the . A + /// is only added if the last item that was added to the exists and is not a + /// . + /// + /// The itself. + IContextMenuBuilder AddSeparator(); + + /// + /// Adds a custom item to the . + /// + /// The custom to add to the . + /// The itself. + IContextMenuBuilder AddCustomItem(StrictContextMenuItem item); + + /// + /// Obtain the , which has been constructed by using the other methods of + /// . + /// + /// The constructed . + ContextMenuStrip Build(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ContextMenu/IContextMenuBuilderProvider.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ContextMenu/IContextMenuBuilderProvider.cs (revision 0) +++ Core/Gui/src/Core.Gui/ContextMenu/IContextMenuBuilderProvider.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; +using Core.Common.Controls.TreeView; + +namespace Core.Gui.ContextMenu +{ + /// + /// Interface which describes classes that are able to provide a . + /// + public interface IContextMenuBuilderProvider + { + /// + /// Returns a new for creating a + /// for the given . + /// + /// The data object to have the + /// create a for. + /// The to use while executing the + /// actions. + /// The which can be used to create a + /// for . + /// Thrown when the instance could + /// not be created. + IContextMenuBuilder Get(object value, TreeViewControl treeViewControl); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ContextMenu/StrictContextMenuItem.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ContextMenu/StrictContextMenuItem.cs (revision 0) +++ Core/Gui/src/Core.Gui/ContextMenu/StrictContextMenuItem.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,55 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; + +namespace Core.Gui.ContextMenu +{ + /// + /// Class used by the to enforce instantiation of the following properties: + /// + /// + /// + /// + /// + /// + /// + public sealed class StrictContextMenuItem : ToolStripMenuItem + { + /// + /// Creates a new instance of . + /// + /// The text of the . + /// The tooltip of the . + /// The icon used for the . + /// The handler for a mouse click on the created + /// . + public StrictContextMenuItem(string text, string toolTip, Image image, EventHandler clickHandler) + { + Text = text; + ToolTipText = toolTip; + Image = image; + Click += clickHandler; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ContextMenu/TreeViewContextMenuItemFactory.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ContextMenu/TreeViewContextMenuItemFactory.cs (revision 0) +++ Core/Gui/src/Core.Gui/ContextMenu/TreeViewContextMenuItemFactory.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,146 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; +using Core.Common.Controls.TreeView; +using Core.Gui.Properties; + +namespace Core.Gui.ContextMenu +{ + /// + /// This class represents a factory for creating . + /// + internal class TreeViewContextMenuItemFactory + { + private readonly object dataObject; + private readonly TreeViewControl treeViewControl; + + /// + /// Creates a new instance of for the given . + /// + /// The data object for which to create the objects. + /// The to use while executing the actions. + /// Thrown when or is null. + public TreeViewContextMenuItemFactory(object dataObject, TreeViewControl treeViewControl) + { + if (dataObject == null) + { + throw new ArgumentNullException(nameof(dataObject), Resources.ContextMenuItemFactory_Can_not_create_context_menu_items_without_data); + } + + if (treeViewControl == null) + { + throw new ArgumentNullException(nameof(treeViewControl), Resources.ContextMenuItemFactory_Can_not_create_context_menu_items_without_tree_view_control); + } + + this.dataObject = dataObject; + this.treeViewControl = treeViewControl; + } + + /// + /// Creates a which is bound to the action of renaming + /// the . + /// + /// The created . + public ToolStripItem CreateRenameItem() + { + var toolStripMenuItem = new ToolStripMenuItem(Resources.Rename) + { + ToolTipText = Resources.Rename_ToolTip, + Image = Resources.RenameIcon, + Enabled = treeViewControl.CanRenameNodeForData(dataObject) + }; + toolStripMenuItem.Click += (s, e) => treeViewControl.TryRenameNodeForData(dataObject); + return toolStripMenuItem; + } + + /// + /// Creates a which is bound to the action of deleting + /// the . + /// + /// The created . + public ToolStripItem CreateDeleteItem() + { + var toolStripMenuItem = new ToolStripMenuItem(Resources.Delete) + { + ToolTipText = Resources.Delete_ToolTip, + Image = Resources.DeleteIcon, + Enabled = treeViewControl.CanRemoveNodeForData(dataObject) + }; + toolStripMenuItem.Click += (s, e) => treeViewControl.TryRemoveNodeForData(dataObject); + return toolStripMenuItem; + } + + /// + /// Creates a which is bound to the action of deleting + /// the children of . + /// + /// The created . + public ToolStripItem CreateDeleteChildrenItem() + { + var toolStripMenuItem = new ToolStripMenuItem(Resources.DeleteChildren) + { + ToolTipText = treeViewControl.CanRemoveChildNodesOfData(dataObject) + ? Resources.DeleteChildren_WithChildren_ToolTip + : Resources.DeleteChildren_WithoutChildren_ToolTip, + Image = Resources.DeleteChildrenIcon, + Enabled = treeViewControl.CanRemoveChildNodesOfData(dataObject) + }; + toolStripMenuItem.Click += (s, e) => treeViewControl.TryRemoveChildNodesOfData(dataObject); + return toolStripMenuItem; + } + + /// + /// Creates a which is bound to the action of expanding + /// the . + /// + /// The created . + public ToolStripItem CreateExpandAllItem() + { + var toolStripMenuItem = new ToolStripMenuItem(Resources.Expand_all) + { + ToolTipText = Resources.Expand_all_ToolTip, + Image = Resources.ExpandAllIcon, + Enabled = treeViewControl.CanExpandOrCollapseForData(dataObject) + }; + toolStripMenuItem.Click += (s, e) => treeViewControl.TryExpandAllNodesForData(dataObject); + return toolStripMenuItem; + } + + /// + /// Creates a which is bound to the action of collapsing + /// the . + /// + /// The created . + public ToolStripItem CreateCollapseAllItem() + { + var toolStripMenuItem = new ToolStripMenuItem(Resources.Collapse_all) + { + ToolTipText = Resources.Collapse_all_ToolTip, + Image = Resources.CollapseAllIcon, + Enabled = treeViewControl.CanExpandOrCollapseForData(dataObject) + }; + toolStripMenuItem.Click += (s, e) => treeViewControl.TryCollapseAllNodesForData(dataObject); + return toolStripMenuItem; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Converters/ColorTypeConverter.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Converters/ColorTypeConverter.cs (revision 0) +++ Core/Gui/src/Core.Gui/Converters/ColorTypeConverter.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,37 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Drawing; + +namespace Core.Gui.Converters +{ + /// + /// A type converter to convert color objects to and from various other representations. + /// + public class ColorTypeConverter : ColorConverter + { + public override bool GetStandardValuesSupported(ITypeDescriptorContext context) + { + return false; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Converters/ExpandableArrayConverter.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Converters/ExpandableArrayConverter.cs (revision 0) +++ Core/Gui/src/Core.Gui/Converters/ExpandableArrayConverter.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,122 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Globalization; +using Core.Gui.Properties; +using Core.Gui.PropertyBag; + +namespace Core.Gui.Converters +{ + /// + /// with modified conversion to string and shows an array + /// starting with index 1 instead of 0. + /// + public class ExpandableArrayConverter : ArrayConverter + { + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + var array = value as Array; + if (destinationType == typeof(string) && array != null) + { + return string.Format(CultureInfo.CurrentCulture, + Resources.ExpandableArrayConverter_ConvertTo_Count_0_, + array.GetLength(0)); + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + PropertyDescriptor[] properties = null; + var array = value as Array; + if (array != null) + { + int length = array.GetLength(0); + properties = new PropertyDescriptor[length]; + + Type type = array.GetType(); + Type elementType = type.GetElementType(); + for (var index = 0; index < length; ++index) + { + properties[index] = CreateElementPropertyDescriptor(type, elementType, index); + } + } + + return new PropertyDescriptorCollection(properties); + } + + /// + /// Creates a new instance of type . + /// + /// Type of the array. + /// Type of the elements in . + /// Index of the element corresponding with this property descriptor. + /// New instance of . + /// + protected virtual PropertyDescriptor CreateElementPropertyDescriptor(Type type, Type elementType, int index) + { + return new ArrayPropertyDescriptor(type, elementType, index); + } + + #region Nested Type: ArrayPropertyDescriptor + + /// + /// Array element property descriptor used by . + /// Properties are named based on their index + 1. + /// + protected class ArrayPropertyDescriptor : SimplePropertyDescriptor + { + private readonly int index; + + /// + /// Initializes a new instance of the class. + /// + /// Type of the array. + /// Type of the elements in . + /// Index of the element corresponding with this property descriptor. + public ArrayPropertyDescriptor(Type arrayType, Type elementType, int elementIndex) + : base(arrayType, "[" + (elementIndex + 1) + "]", elementType, null) + { + index = elementIndex; + } + + public override object GetValue(object component) + { + var array = (Array) component; + return new DynamicPropertyBag(array.GetValue(index)); + } + + public override void SetValue(object component, object value) + { + var array = (Array) component; + array.SetValue(value, index); + // This class is based on the System.ComponentModel.ArrayConverter.ArrayPropertyDescriptor, + // and there the SetValue also called OnValueChanged. Copying that behavior here as well. + OnValueChanged(array, EventArgs.Empty); + } + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Converters/ExpandableReadOnlyArrayConverter.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Converters/ExpandableReadOnlyArrayConverter.cs (revision 0) +++ Core/Gui/src/Core.Gui/Converters/ExpandableReadOnlyArrayConverter.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,38 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using Core.Gui.PropertyBag; + +namespace Core.Gui.Converters +{ + /// + /// that shows a read-only array. + /// + public class ExpandableReadOnlyArrayConverter : ExpandableArrayConverter + { + protected override PropertyDescriptor CreateElementPropertyDescriptor(Type type, Type elementType, int index) + { + return new ReadOnlyPropertyDescriptorDecorator(new ArrayPropertyDescriptor(type, elementType, index)); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,96 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Reflection; +using Core.Common.Base.Data; + +namespace Core.Gui.Converters +{ + /// + /// Attribute when using the to define what is + /// shown as name and value for each element. + /// + [AttributeUsage(AttributeTargets.Property)] + public class KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute : KeyValueElementAttribute + { + private readonly string unitPropertyName; + + /// + /// Creates a new instance of . + /// + /// The name of the property to show as name. + /// The name of the property to show as unit. + /// The name of the property to show as value. + /// Thrown when any parameter is null. + public KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(string namePropertyName, string unitPropertyName, string valuePropertyName) : base(namePropertyName, valuePropertyName) + { + if (unitPropertyName == null) + { + throw new ArgumentNullException(nameof(unitPropertyName)); + } + + this.unitPropertyName = unitPropertyName; + } + + public override string GetName(object source) + { + PropertyInfo unitPropertyInfo = source.GetType().GetProperty(unitPropertyName); + if (unitPropertyInfo == null) + { + throw new ArgumentException($"Unit property '{unitPropertyName}' was not found on type {source.GetType().Name}."); + } + + var unit = Convert.ToString(unitPropertyInfo.GetValue(source, new object[0])); + + return $"{base.GetName(source)} [{unit}]"; + } + + /// + /// Gets the property value from the that is used + /// as value. + /// + /// The source to obtain the property value of. + /// The value used as value of the property. + /// Thrown when the property used for the value of + /// the is not found on the + /// or if the value is not of type RoundedDouble + /// + public override string GetValue(object source) + { + PropertyInfo valuePropertyInfo = source.GetType().GetProperty(ValuePropertyName); + if (valuePropertyInfo == null) + { + throw new ArgumentException($"Value property '{ValuePropertyName}' was not found on type {source.GetType().Name}."); + } + + object valueProperty = valuePropertyInfo.GetValue(source, new object[0]); + if (!(valueProperty is RoundedDouble)) + { + throw new ArgumentException($"Value property '{ValuePropertyName}' was not of type RoundedDouble."); + } + + var doubleValue = (RoundedDouble) valueProperty; + return doubleValue.ToString("0.#####", CultureInfo.CurrentCulture); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Converters/KeyValueElementAttribute.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Converters/KeyValueElementAttribute.cs (revision 0) +++ Core/Gui/src/Core.Gui/Converters/KeyValueElementAttribute.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,103 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Reflection; + +namespace Core.Gui.Converters +{ + /// + /// Attribute when using the to define what is + /// shown as name and value for each element. + /// + [AttributeUsage(AttributeTargets.Property)] + public class KeyValueElementAttribute : Attribute + { + private readonly string namePropertyName; + + /// + /// Creates a new instance of . + /// + /// The name of the property to show as name. + /// The name of the property to show as value. + /// Thrown when any parameter is null. + public KeyValueElementAttribute(string namePropertyName, string valuePropertyName) + { + if (namePropertyName == null) + { + throw new ArgumentNullException(nameof(namePropertyName)); + } + + if (valuePropertyName == null) + { + throw new ArgumentNullException(nameof(valuePropertyName)); + } + + this.namePropertyName = namePropertyName; + ValuePropertyName = valuePropertyName; + } + + /// + /// Gets the property value from the that is used + /// as name. + /// + /// The source to obtain the property value of. + /// The value used as name of the property. + /// Thrown when the property used for the name of + /// the is not found on the . + /// + public virtual string GetName(object source) + { + PropertyInfo namePropertyInfo = source.GetType().GetProperty(namePropertyName); + if (namePropertyInfo == null) + { + throw new ArgumentException($"Name property '{namePropertyName}' was not found on type {source.GetType().Name}."); + } + + return Convert.ToString(namePropertyInfo.GetValue(source, new object[0])); + } + + /// + /// Gets the property value from the that is used + /// as value. + /// + /// The source to obtain the property value of. + /// The value used as value of the property. + /// Thrown when the property used for the value of + /// the is not found on the . + /// + public virtual string GetValue(object source) + { + PropertyInfo valuePropertyInfo = source.GetType().GetProperty(ValuePropertyName); + if (valuePropertyInfo == null) + { + throw new ArgumentException($"Value property '{ValuePropertyName}' was not found on type {source.GetType().Name}."); + } + + return Convert.ToString(valuePropertyInfo.GetValue(source, new object[0])); + } + + /// + /// Gets the name of the property to show as value. + /// + protected string ValuePropertyName { get; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Converters/KeyValueExpandableArrayConverter.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Converters/KeyValueExpandableArrayConverter.cs (revision 0) +++ Core/Gui/src/Core.Gui/Converters/KeyValueExpandableArrayConverter.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,118 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Globalization; +using Core.Gui.Properties; + +namespace Core.Gui.Converters +{ + /// + /// Defines a converter for arrays with elements. Properties generated for the array elements uses one + /// of the element's properties as a name and one of the element's properties as a value. + /// + public class KeyValueExpandableArrayConverter : ArrayConverter + { + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + var array = value as Array; + if (destinationType == typeof(string) && array != null) + { + return string.Format(CultureInfo.CurrentCulture, + Resources.ExpandableArrayConverter_ConvertTo_Count_0_, + array.GetLength(0)); + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + var keyValueAttribute = context?.PropertyDescriptor?.Attributes?[typeof(KeyValueElementAttribute)] as KeyValueElementAttribute; + + if (keyValueAttribute == null) + { + throw new ArgumentException($"The {typeof(KeyValueExpandableArrayConverter).Name} can only be used on properties that have the " + + $"{typeof(KeyValueElementAttribute).Name} defined."); + } + + PropertyDescriptor[] properties = null; + var array = value as Array; + if (array != null) + { + Type type = array.GetType(); + Type elementType = type.GetElementType(); + + int length = array.GetLength(0); + properties = new PropertyDescriptor[length]; + + for (var index = 0; index < length; ++index) + { + object source = array.GetValue(index); + properties[index] = new ArrayPropertyDescriptor(elementType, keyValueAttribute.GetName(source), keyValueAttribute.GetValue(source)); + } + } + + return new PropertyDescriptorCollection(properties); + } + + /// + /// Array element property descriptor used by . + /// Properties are named based on the first item in the provided tuple and the value is + /// based on the second item. + /// + private class ArrayPropertyDescriptor : SimplePropertyDescriptor + { + private readonly object propertyValue; + + /// + /// Creates a new instance of . + /// + /// The type of elements of the array. + /// The name of the property. + /// The value of the property. + public ArrayPropertyDescriptor(Type elementType, string name, object value) + : base(elementType, name, value.GetType()) + { + propertyValue = value; + } + + public override bool IsReadOnly + { + get + { + return true; + } + } + + public override object GetValue(object component) + { + return propertyValue; + } + + public override void SetValue(object component, object value) + { + throw new NotSupportedException(); + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Converters/PngToIconConverter.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Converters/PngToIconConverter.cs (revision 0) +++ Core/Gui/src/Core.Gui/Converters/PngToIconConverter.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Windows.Data; +using System.Windows.Media.Imaging; +using Core.Common.Util.Drawing; + +namespace Core.Gui.Converters +{ + /// + /// Converter to change a instance to a instance. + /// + public class PngToIconConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return ((Bitmap) value).AsBitmapImage(); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Core.Gui.csproj =================================================================== diff -u --- Core/Gui/src/Core.Gui/Core.Gui.csproj (revision 0) +++ Core/Gui/src/Core.Gui/Core.Gui.csproj (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + Copying.Lesser.licenseheader + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.0.2000 + true + all + + + 4.4.0 + true + all + + + 2.0.12 + true + all + + + 2.4.4 + true + all + + + 1.1.31 + true + all + + + + + True + True + Resources.resx + + + UserControl + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + + + + + + + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/ExceptionDialog.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ExceptionDialog.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/ExceptionDialog.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,140 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui +{ + partial class ExceptionDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 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(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExceptionDialog)); + this.buttonRestart = new System.Windows.Forms.Button(); + this.buttonCopyTextToClipboard = new System.Windows.Forms.Button(); + this.exceptionTextBox = new System.Windows.Forms.RichTextBox(); + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + this.buttonExit = new System.Windows.Forms.Button(); + this.buttonOpenLog = new System.Windows.Forms.Button(); + this.buttonSaveProject = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // buttonRestart + // + resources.ApplyResources(this.buttonRestart, "buttonRestart"); + this.buttonRestart.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonRestart.Name = "buttonRestart"; + this.buttonRestart.UseVisualStyleBackColor = true; + this.buttonRestart.Click += new System.EventHandler(this.ButtonRestartClick); + // + // buttonCopyTextToClipboard + // + resources.ApplyResources(this.buttonCopyTextToClipboard, "buttonCopyTextToClipboard"); + this.buttonCopyTextToClipboard.Name = "buttonCopyTextToClipboard"; + this.buttonCopyTextToClipboard.UseVisualStyleBackColor = true; + this.buttonCopyTextToClipboard.Click += new System.EventHandler(this.ButtonCopyTextToClipboardClick); + // + // exceptionTextBox + // + resources.ApplyResources(this.exceptionTextBox, "exceptionTextBox"); + this.exceptionTextBox.BackColor = System.Drawing.SystemColors.ControlLight; + this.exceptionTextBox.ForeColor = System.Drawing.Color.Black; + this.exceptionTextBox.Name = "exceptionTextBox"; + this.exceptionTextBox.ReadOnly = true; + // + // richTextBox1 + // + resources.ApplyResources(this.richTextBox1, "richTextBox1"); + this.richTextBox1.BackColor = System.Drawing.SystemColors.ButtonFace; + this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.ReadOnly = true; + // + // buttonExit + // + resources.ApplyResources(this.buttonExit, "buttonExit"); + this.buttonExit.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonExit.Name = "buttonExit"; + this.buttonExit.UseVisualStyleBackColor = true; + this.buttonExit.Click += new System.EventHandler(this.ButtonExitClick); + // + // buttonOpenLog + // + resources.ApplyResources(this.buttonOpenLog, "buttonOpenLog"); + this.buttonOpenLog.Name = "buttonOpenLog"; + this.buttonOpenLog.UseVisualStyleBackColor = true; + this.buttonOpenLog.Click += new System.EventHandler(this.ButtonOpenLogClick); + // + // buttonSaveProject + // + resources.ApplyResources(this.buttonSaveProject, "buttonSaveProject"); + this.buttonSaveProject.Name = "buttonSaveProject"; + this.buttonSaveProject.UseVisualStyleBackColor = true; + this.buttonSaveProject.Click += new System.EventHandler(this.ButtonSaveProjectClick); + // + // ExceptionDialog + // + this.AcceptButton = this.buttonRestart; + resources.ApplyResources(this, "$this"); + this.Controls.Add(this.buttonOpenLog); + this.Controls.Add(this.buttonExit); + this.Controls.Add(this.exceptionTextBox); + this.Controls.Add(this.richTextBox1); + this.Controls.Add(this.buttonCopyTextToClipboard); + this.Controls.Add(this.buttonRestart); + this.Controls.Add(this.buttonSaveProject); + this.Name = "ExceptionDialog"; + this.ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.Button buttonRestart; + private System.Windows.Forms.Button buttonCopyTextToClipboard; + private System.Windows.Forms.RichTextBox exceptionTextBox; + private System.Windows.Forms.RichTextBox richTextBox1; + private System.Windows.Forms.Button buttonExit; + private System.Windows.Forms.Button buttonOpenLog; + private System.Windows.Forms.Button buttonSaveProject; + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ExceptionDialog.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ExceptionDialog.cs (revision 0) +++ Core/Gui/src/Core.Gui/ExceptionDialog.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,132 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; +using Core.Common.Controls.Dialogs; +using Core.Gui.Clipboard; +using Core.Gui.Commands; +using Core.Gui.Properties; + +namespace Core.Gui +{ + /// + /// Class for showing an exception dialog. + /// The exception dialog can return the following results: + /// + /// + /// : this result represents a request for restarting the application. + /// + /// + /// : this result represents a request for closing the application. + /// + /// + /// + public partial class ExceptionDialog : DialogBase + { + private readonly ICommandsOwner commands; + private Action openLogClicked; + + /// + /// Constructs a new . + /// + /// The owner of the dialog. + /// The commands available in the application. + /// The exception to show in the dialog. + public ExceptionDialog(IWin32Window dialogParent, ICommandsOwner commands, Exception exception) : base(dialogParent, Resources.bug_exclamation, 470, 200) + { + this.commands = commands; + InitializeComponent(); + + buttonOpenLog.Enabled = false; + exceptionTextBox.Text = exception?.ToString() ?? ""; + } + + /// + /// Gets or sets the action that should be performed after clicking the log button. + /// + /// The log button is only enabled when this action is set. + public Action OpenLogClicked + { + private get + { + return openLogClicked; + } + set + { + openLogClicked = value; + + buttonOpenLog.Enabled = openLogClicked != null; + } + } + + protected override Button GetCancelButton() + { + return buttonExit; + } + + private void ButtonRestartClick(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + + Close(); + } + + private void ButtonExitClick(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + + Close(); + } + + private void ButtonCopyTextToClipboardClick(object sender, EventArgs e) + { + ClipboardProvider.Clipboard.SetDataObject(exceptionTextBox.Text, true); + } + + private void ButtonOpenLogClick(object sender, EventArgs e) + { + OpenLogClicked(); + } + + private void ButtonSaveProjectClick(object sender, EventArgs e) + { + bool saved; + try + { + saved = commands.StorageCommands.SaveProjectAs(); + } + catch (Exception) + { + saved = false; + } + + ShowMessageDialog( + saved ? Resources.ExceptionDialog_ButtonSaveProjectClick_Successfully_saved_project : Resources.ExceptionDialog_ButtonSaveProjectClick_Saving_project_failed, + saved ? Resources.ExceptionDialog_ButtonSaveProjectClick_Successfully_saved_project_caption : Resources.ExceptionDialog_ButtonSaveProjectClick_Saving_project_failed_caption); + } + + private static void ShowMessageDialog(string message, string caption) + { + MessageBox.Show(message, caption, MessageBoxButtons.OK); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ExceptionDialog.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/ExceptionDialog.resx (revision 0) +++ Core/Gui/src/Core.Gui/ExceptionDialog.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Bottom, Right + + + + 449, 242 + + + 75, 23 + + + + 2 + + + Herstarten + + + buttonRestart + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Bottom, Left + + + 12, 242 + + + 127, 23 + + + 4 + + + Kopieer naar klembord + + + buttonCopyTextToClipboard + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Top, Bottom, Left, Right + + + 12, 27 + + + 512, 209 + + + 3 + + + + + + exceptionTextBox + + + System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Top, Left, Right + + + 12, 8 + + + 483, 20 + + + 3 + + + Een onafgehandelde fout is opgetreden. Het programma moet gesloten worden. + + + richTextBox1 + + + System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Bottom, Right + + + 368, 242 + + + 75, 23 + + + 1 + + + Afsluiten + + + buttonExit + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Bottom, Left + + + 145, 242 + + + 104, 23 + + + 6 + + + Open logbestand + + + buttonOpenLog + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + Bottom, Right + + + 287, 242 + + + 75, 23 + + + 7 + + + Opslaan als + + + buttonSaveProject + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + True + + + 536, 273 + + + CenterParent + + + Kritieke fout + + + ExceptionDialog + + + Core.Common.Controls.Dialogs.DialogBase, Core.Common.Controls, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MainWindow/IMainWindow.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MainWindow/IMainWindow.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MainWindow/IMainWindow.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,42 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; +using Core.Common.Controls.Views; + +namespace Core.Gui.Forms.MainWindow +{ + /// + /// Interface for the main user interface window of the application. + /// + public interface IMainWindow : IWin32Window + { + /// + /// Gets the property grid tool window. + /// + IView PropertyGrid { get; } + + /// + /// Initializes and shows the property grid tool window. + /// + void InitPropertiesWindowOrBringToFront(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindow.xaml =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindow.xaml (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindow.xaml (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindow.xaml.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindow.xaml.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindow.xaml.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,486 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Input; +using System.Windows.Interop; +using System.Windows.Media.Imaging; +using Core.Common.Controls.Views; +using Core.Common.Util.Settings; +using Core.Gui.Commands; +using Core.Gui.Forms.MessageWindow; +using Core.Gui.Forms.ViewHost; +using Core.Gui.Selection; +using Core.Gui.Settings; + +namespace Core.Gui.Forms.MainWindow +{ + /// + /// Main user interface of the application. + /// + public partial class MainWindow : IMainWindow, IDisposable, ISynchronizeInvoke + { + /// + /// Class to help with hybrid winforms - WPF applications. Provides UI handle to + /// ensure common UI functionality such as maximizing works as expected. + /// + private readonly WindowInteropHelper windowInteropHelper; + + private IViewController viewController; + private ICommandsOwner commands; + private ISettingsOwner settings; + private IApplicationSelection applicationSelection; + + private MessageWindow.MessageWindow messageWindow; + private PropertyGridView.PropertyGridView propertyGrid; + + private IGui gui; + private ProjectExplorer.ProjectExplorer projectExplorer; + + /// + /// Initializes a new instance of the class. + /// + public MainWindow() + { + InitializeComponent(); + + windowInteropHelper = new WindowInteropHelper(this); + Name = "RiskeerMainWindow"; + } + + /// + /// Gets a value indicating whether this window is disposed. + /// + public bool IsWindowDisposed { get; private set; } + + /// + /// Gets the log messages tool window. + /// + public IMessageWindow MessageWindow => messageWindow; + + /// + /// Gets the view host. + /// + public IViewHost ViewHost => AvalonDockViewHost; + + /// + /// Gets or sets a value indicating whether or not the main user interface is visible. + /// + /// Thrown when no gui has been set using . + public bool Visible + { + get => IsVisible; + set + { + if (gui == null) + { + throw new InvalidOperationException("First call 'SetGui(IGui)' before setting a value on this property."); + } + + if (value) + { + if (IsVisible) + { + return; + } + + Show(); + } + else + { + if (!IsVisible) + { + return; + } + + Hide(); + } + } + } + + public IView PropertyGrid => propertyGrid; + + public IntPtr Handle => windowInteropHelper.Handle; + + public bool InvokeRequired => !Dispatcher.CheckAccess(); + + public ProjectExplorer.ProjectExplorer ProjectExplorer => projectExplorer; + + /// + /// Sets the and dependencies. + /// + public void SetGui(IGui value) + { + gui = value; + + viewController = gui; + settings = gui; + commands = gui; + applicationSelection = gui; + } + + /// + /// Subscribes the main user interface to the provided by . + /// + public void SubscribeToGui() + { + if (viewController?.ViewHost != null) + { + viewController.ViewHost.ViewClosed += OnViewClosed; + } + } + + /// + /// Unsubscribes the main user interface from the provided by . + /// + public void UnsubscribeFromGui() + { + if (viewController?.ViewHost != null) + { + viewController.ViewHost.ViewClosed -= OnViewClosed; + } + } + + /// + /// Initializes and shows all the tool windows. + /// + /// + /// When a hasn't been set with . + /// + public void InitializeToolWindows() + { + InitProjectExplorerWindowOrBringToFront(); + InitMessagesWindowOrBringToFront(); + InitPropertiesWindowOrBringToFront(); + } + + public void ValidateItems() + { + if (gui == null) + { + return; + } + + UpdateToolWindowButtonState(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Initializes and shows the property grid tool window. + /// + /// + /// When a hasn't been set with . + /// + public void InitPropertiesWindowOrBringToFront() + { + if (gui == null) + { + throw new InvalidOperationException("Must call 'SetGui(IGui)' before calling 'InitPropertiesWindowAndActivate'."); + } + + if (propertyGrid == null) + { + propertyGrid = new PropertyGridView.PropertyGridView(gui.PropertyResolver) + { + Text = Properties.Resources.Properties_Title, + Data = applicationSelection.Selection + }; + + viewController.ViewHost.AddToolView(propertyGrid, ToolViewLocation.Right); + viewController.ViewHost.SetImage(propertyGrid, Properties.Resources.PropertiesPanelIcon); + } + else + { + viewController.ViewHost.BringToFront(propertyGrid); + } + } + + /// + /// Updates the data of the . + /// + public void UpdateProjectExplorer() + { + if (ProjectExplorer != null) + { + ProjectExplorer.Data = gui.Project; + } + } + + protected virtual void Dispose(bool disposing) + { + if (IsWindowDisposed || !disposing) + { + return; + } + + IsWindowDisposed = true; + + Close(); + + SetGui(null); + } + + private void OnViewClosed(object sender, ViewChangeEventArgs e) + { + if (ReferenceEquals(e.View, propertyGrid)) + { + propertyGrid = null; + } + + if (ReferenceEquals(e.View, messageWindow)) + { + messageWindow = null; + } + + if (ReferenceEquals(e.View, projectExplorer)) + { + projectExplorer = null; + } + } + + private void UpdateToolWindowButtonState() + { + if (viewController.ViewHost != null) + { + ButtonShowProjectExplorer.IsChecked = viewController.ViewHost.ToolViews.Contains(ProjectExplorer); + ButtonShowMessages.IsChecked = viewController.ViewHost.ToolViews.Contains(MessageWindow); + ButtonShowProperties.IsChecked = viewController.ViewHost.ToolViews.Contains(PropertyGrid); + } + } + + private void InitProjectExplorerWindowOrBringToFront() + { + if (gui == null) + { + throw new InvalidOperationException("Must call 'SetGui(IGui)' before calling 'InitMessagesWindowOrActivate'."); + } + + if (projectExplorer == null) + { + projectExplorer = new ProjectExplorer.ProjectExplorer(gui.ViewCommands, gui.GetTreeNodeInfos()) + { + Data = gui.Project + }; + viewController.ViewHost.AddToolView(projectExplorer, ToolViewLocation.Left); + viewController.ViewHost.SetImage(projectExplorer, Properties.Resources.ProjectExplorerIcon); + } + else + { + viewController.ViewHost.BringToFront(projectExplorer); + } + } + + private void InitMessagesWindowOrBringToFront() + { + if (gui == null) + { + throw new InvalidOperationException("Must call 'SetGui(IGui)' before calling 'InitMessagesWindowOrActivate'."); + } + + if (messageWindow == null) + { + messageWindow = new MessageWindow.MessageWindow(this) + { + Text = Properties.Resources.Messages + }; + viewController.ViewHost.AddToolView(messageWindow, ToolViewLocation.Bottom); + viewController.ViewHost.SetImage(messageWindow, Properties.Resources.application_view_list); + } + else + { + viewController.ViewHost.BringToFront(messageWindow); + } + } + + private void OnFileSaveClicked(object sender, RoutedEventArgs e) + { + commands.StorageCommands.SaveProject(); + } + + private void OnFileSaveAsClicked(object sender, RoutedEventArgs e) + { + commands.StorageCommands.SaveProjectAs(); + } + + private void OnFileOpenClicked(object sender, RoutedEventArgs e) + { + string projectPath = commands.StorageCommands.GetExistingProjectFilePath(); + if (!string.IsNullOrEmpty(projectPath)) + { + commands.StorageCommands.OpenExistingProject(projectPath); + } + } + + private void OnFileNewClicked(object sender, RoutedEventArgs e) + { + commands.StorageCommands.CreateNewProject(); + ValidateItems(); + } + + private void OnFileExitClicked(object sender, RoutedEventArgs e) + { + gui.ExitApplication(); + } + + private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) + { + WindowState = WindowState.Maximized; + + FileManualButton.IsEnabled = File.Exists(settings.FixedSettings.ManualFilePath); + + ValidateItems(); + } + + private void ButtonShowProjectExplorer_Click(object sender, RoutedEventArgs e) + { + bool active = viewController.ViewHost.ToolViews.Contains(ProjectExplorer); + + if (active) + { + viewController.ViewHost.Remove(ProjectExplorer); + } + else + { + InitProjectExplorerWindowOrBringToFront(); + } + + ButtonShowProjectExplorer.IsChecked = !active; + } + + private void ButtonShowProperties_Click(object sender, RoutedEventArgs e) + { + bool active = viewController.ViewHost.ToolViews.Contains(PropertyGrid); + + if (active) + { + viewController.ViewHost.Remove(PropertyGrid); + } + else + { + InitPropertiesWindowOrBringToFront(); + } + + ButtonShowProperties.IsChecked = !active; + } + + private void ButtonShowMessages_Click(object sender, RoutedEventArgs e) + { + bool active = viewController.ViewHost.ToolViews.Contains(MessageWindow); + + if (active) + { + viewController.ViewHost.Remove(MessageWindow); + } + else + { + InitMessagesWindowOrBringToFront(); + } + + ButtonShowMessages.IsChecked = !active; + } + + private void OnFileHelpShowLog_Clicked(object sender, RoutedEventArgs e) + { + commands.ApplicationCommands.OpenLogFileExternal(); + } + + private void OnFileManual_Clicked(object sender, RoutedEventArgs e) + { + string manualFileName = settings.FixedSettings.ManualFilePath; + + if (File.Exists(manualFileName)) + { + Process.Start(manualFileName); + } + } + + private void CloseDocumentTab(object sender, ExecutedRoutedEventArgs e) + { + viewController.ViewHost.Remove(viewController.ViewHost.ActiveDocumentView); + } + + private void CanCloseDocumentTab(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = viewController.ViewHost.DocumentViews.Any(); + } + + private void OnAboutDialog_Clicked(object sender, RoutedEventArgs e) + { + var aboutDialog = new SplashScreen.SplashScreen + { + VersionText = SettingsHelper.Instance.ApplicationVersion, + SupportEmail = settings.FixedSettings.SupportEmailAddress, + SupportPhoneNumber = settings.FixedSettings.SupportPhoneNumber, + AllowsTransparency = false, + WindowStyle = WindowStyle.SingleBorderWindow, + Title = Properties.Resources.ViewStateBar_About_ToolTip, + Icon = Imaging.CreateBitmapSourceFromHBitmap(Properties.Resources.information.GetHbitmap(), + IntPtr.Zero, + Int32Rect.Empty, + BitmapSizeOptions.FromEmptyOptions()), + ShowInTaskbar = false, + Owner = this, + WindowStartupLocation = WindowStartupLocation.CenterOwner + }; + + aboutDialog.PreviewKeyDown += (s, ev) => + { + if (ev.Key == Key.Escape) + { + ev.Handled = true; + aboutDialog.Shutdown(); + } + }; + + aboutDialog.ShowDialog(); + } + + #region Implementation: ISynchronizeInvoke + + public IAsyncResult BeginInvoke(Delegate method, object[] args) + { + Dispatcher.BeginInvoke(method, args); + return null; + } + + public object EndInvoke(IAsyncResult result) + { + throw new NotImplementedException(); + } + + public object Invoke(Delegate method, object[] args) + { + return Dispatcher.Invoke(method, args); + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindowCommands.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindowCommands.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MainWindow/MainWindowCommands.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,36 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Input; + +namespace Core.Gui.Forms.MainWindow +{ + /// + /// This class defines members for the custom commands of . + /// + public static class MainWindowCommands + { + /// + /// The command for closing the current active view. + /// + public static readonly RoutedUICommand CloseViewTabCommand = new RoutedUICommand(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/IMessageWindow.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/IMessageWindow.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/IMessageWindow.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,42 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Controls.Views; +using log4net.Core; + +namespace Core.Gui.Forms.MessageWindow +{ + /// + /// Interface declaring the members for a view that can show log messages. + /// + public interface IMessageWindow : IView + { + /// + /// Adds a logging message to the view. + /// + /// Type of logging message. + /// Time when the message was logged. + /// The message text. + /// Throw when is null. + void AddMessage(Level level, DateTime time, string message); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,344 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; + +namespace Core.Gui.Forms.MessageWindow +{ + partial class MessageWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 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(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MessageWindow)); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.buttonCopy = new System.Windows.Forms.ToolStripMenuItem(); + this.cToolStripMenuItem = new System.Windows.Forms.ToolStripSeparator(); + this.buttonClearAll = new System.Windows.Forms.ToolStripMenuItem(); + this.levelImages = new System.Windows.Forms.ImageList(this.components); + this.messagesToolStrip = new System.Windows.Forms.ToolStrip(); + this.buttonShowInfo = new System.Windows.Forms.ToolStripButton(); + this.buttonShowWarning = new System.Windows.Forms.ToolStripButton(); + this.buttonShowError = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.buttonShowDetails = new System.Windows.Forms.ToolStripButton(); + this.messagesDataGridView = new System.Windows.Forms.DataGridView(); + this.levelColumnDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewImageColumn(); + this.timeColumnDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.messageColumnDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.fullMessageColumnDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.messagesBindingSource = new System.Windows.Forms.BindingSource(this.components); + this.messageWindowData = new System.Data.DataSet(); + this.Messages = new System.Data.DataTable(); + this.levelColumn = new System.Data.DataColumn(); + this.timeColumn = new System.Data.DataColumn(); + this.messageColumn = new System.Data.DataColumn(); + this.fullMessageColumn = new System.Data.DataColumn(); + this.contextMenu.SuspendLayout(); + this.messagesToolStrip.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.messagesDataGridView)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.messagesBindingSource)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.messageWindowData)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.Messages)).BeginInit(); + this.SuspendLayout(); + // + // contextMenu + // + this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.buttonCopy, + this.cToolStripMenuItem, + this.buttonClearAll}); + this.contextMenu.Name = "contextMenu"; + resources.ApplyResources(this.contextMenu, "contextMenu"); + // + // buttonCopy + // + this.buttonCopy.Image = global::Core.Gui.Properties.Resources.CopyHS; + this.buttonCopy.Name = "buttonCopy"; + resources.ApplyResources(this.buttonCopy, "buttonCopy"); + this.buttonCopy.Click += new System.EventHandler(this.ButtonCopyClick); + // + // cToolStripMenuItem + // + this.cToolStripMenuItem.Name = "cToolStripMenuItem"; + resources.ApplyResources(this.cToolStripMenuItem, "cToolStripMenuItem"); + // + // buttonClearAll + // + this.buttonClearAll.Image = global::Core.Gui.Properties.Resources.icon_clear_all_messages; + this.buttonClearAll.Name = "buttonClearAll"; + resources.ApplyResources(this.buttonClearAll, "buttonClearAll"); + this.buttonClearAll.Click += new System.EventHandler(this.ButtonClearAllClick); + // + // levelImages + // + this.levelImages.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("levelImages.ImageStream"))); + this.levelImages.TransparentColor = System.Drawing.Color.Transparent; + this.levelImages.Images.SetKeyName(0, "exclamation.png"); + this.levelImages.Images.SetKeyName(1, "information.png"); + this.levelImages.Images.SetKeyName(2, "error.png"); + this.levelImages.Images.SetKeyName(3, "debug.png"); + // + // messagesToolStrip + // + this.messagesToolStrip.BackColor = System.Drawing.SystemColors.ControlLight; + resources.ApplyResources(this.messagesToolStrip, "messagesToolStrip"); + this.messagesToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.messagesToolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.buttonShowInfo, + this.buttonShowWarning, + this.buttonShowError, + this.toolStripSeparator1, + this.buttonShowDetails}); + this.messagesToolStrip.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.HorizontalStackWithOverflow; + this.messagesToolStrip.Name = "messagesToolStrip"; + // + // buttonShowInfo + // + this.buttonShowInfo.Checked = true; + this.buttonShowInfo.CheckState = System.Windows.Forms.CheckState.Checked; + this.buttonShowInfo.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonShowInfo.Image = global::Core.Gui.Properties.Resources.information; + resources.ApplyResources(this.buttonShowInfo, "buttonShowInfo"); + this.buttonShowInfo.Name = "buttonShowInfo"; + this.buttonShowInfo.Click += new System.EventHandler(this.ButtonShowInfoClick); + // + // buttonShowWarning + // + this.buttonShowWarning.Checked = true; + this.buttonShowWarning.CheckState = System.Windows.Forms.CheckState.Checked; + this.buttonShowWarning.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonShowWarning.Image = global::Core.Gui.Properties.Resources.error; + resources.ApplyResources(this.buttonShowWarning, "buttonShowWarning"); + this.buttonShowWarning.Name = "buttonShowWarning"; + this.buttonShowWarning.Click += new System.EventHandler(this.ButtonShowWarningClick); + // + // buttonShowError + // + this.buttonShowError.Checked = true; + this.buttonShowError.CheckState = System.Windows.Forms.CheckState.Checked; + this.buttonShowError.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonShowError.Image = global::Core.Gui.Properties.Resources.exclamation; + resources.ApplyResources(this.buttonShowError, "buttonShowError"); + this.buttonShowError.Name = "buttonShowError"; + this.buttonShowError.Click += new System.EventHandler(this.ButtonShowErrorClick); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + resources.ApplyResources(this.toolStripSeparator1, "toolStripSeparator1"); + // + // buttonShowDetails + // + this.buttonShowDetails.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonShowDetails.Image = global::Core.Gui.Properties.Resources.application_import_blue; + resources.ApplyResources(this.buttonShowDetails, "buttonShowDetails"); + this.buttonShowDetails.Name = "buttonShowDetails"; + this.buttonShowDetails.Click += new System.EventHandler(this.ButtonShowDetailsClick); + // + // messagesDataGridView + // + this.messagesDataGridView.AllowUserToAddRows = false; + this.messagesDataGridView.AllowUserToDeleteRows = false; + this.messagesDataGridView.AllowUserToResizeColumns = false; + this.messagesDataGridView.AllowUserToResizeRows = false; + this.messagesDataGridView.AutoGenerateColumns = false; + this.messagesDataGridView.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.DisplayedCells; + this.messagesDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + this.messagesDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.levelColumnDataGridViewTextBoxColumn, + this.timeColumnDataGridViewTextBoxColumn, + this.messageColumnDataGridViewTextBoxColumn, + this.fullMessageColumnDataGridViewTextBoxColumn}); + this.messagesDataGridView.ContextMenuStrip = this.contextMenu; + this.messagesDataGridView.DataSource = this.messagesBindingSource; + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Window; + dataGridViewCellStyle3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.ControlText; + dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.messagesDataGridView.DefaultCellStyle = dataGridViewCellStyle3; + resources.ApplyResources(this.messagesDataGridView, "messagesDataGridView"); + this.messagesDataGridView.Name = "messagesDataGridView"; + this.messagesDataGridView.ReadOnly = true; + this.messagesDataGridView.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing; + this.messagesDataGridView.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.messagesDataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.messagesDataGridView.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.MessagesDataGridViewCellMouseDoubleClick); + this.messagesDataGridView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MessagesDataGridViewKeyDown); + // + // levelColumnDataGridViewTextBoxColumn + // + this.levelColumnDataGridViewTextBoxColumn.DataPropertyName = "levelColumn"; + resources.ApplyResources(this.levelColumnDataGridViewTextBoxColumn, "levelColumnDataGridViewTextBoxColumn"); + this.levelColumnDataGridViewTextBoxColumn.Name = "levelColumnDataGridViewTextBoxColumn"; + this.levelColumnDataGridViewTextBoxColumn.ReadOnly = true; + this.levelColumnDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.levelColumnDataGridViewTextBoxColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; + // + // timeColumnDataGridViewTextBoxColumn + // + this.timeColumnDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader; + this.timeColumnDataGridViewTextBoxColumn.DataPropertyName = "timeColumn"; + dataGridViewCellStyle1.Format = "HH:mm:ss"; + dataGridViewCellStyle1.NullValue = null; + this.timeColumnDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle1; + resources.ApplyResources(this.timeColumnDataGridViewTextBoxColumn, "timeColumnDataGridViewTextBoxColumn"); + this.timeColumnDataGridViewTextBoxColumn.Name = "timeColumnDataGridViewTextBoxColumn"; + this.timeColumnDataGridViewTextBoxColumn.ReadOnly = true; + this.timeColumnDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + // + // messageColumnDataGridViewTextBoxColumn + // + this.messageColumnDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.messageColumnDataGridViewTextBoxColumn.DataPropertyName = "messageColumn"; + dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.messageColumnDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2; + resources.ApplyResources(this.messageColumnDataGridViewTextBoxColumn, "messageColumnDataGridViewTextBoxColumn"); + this.messageColumnDataGridViewTextBoxColumn.Name = "messageColumnDataGridViewTextBoxColumn"; + this.messageColumnDataGridViewTextBoxColumn.ReadOnly = true; + this.messageColumnDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + // + // fullMessageColumnDataGridViewTextBoxColumn + // + this.fullMessageColumnDataGridViewTextBoxColumn.DataPropertyName = "fullMessageColumn"; + resources.ApplyResources(this.fullMessageColumnDataGridViewTextBoxColumn, "fullMessageColumnDataGridViewTextBoxColumn"); + this.fullMessageColumnDataGridViewTextBoxColumn.Name = "fullMessageColumnDataGridViewTextBoxColumn"; + this.fullMessageColumnDataGridViewTextBoxColumn.ReadOnly = true; + // + // messagesBindingSource + // + this.messagesBindingSource.DataMember = "MessageTable"; + this.messagesBindingSource.DataSource = this.messageWindowData; + this.messagesBindingSource.Sort = ""; + // + // messageWindowData + // + this.messageWindowData.DataSetName = "NewDataSet"; + this.messageWindowData.Tables.AddRange(new System.Data.DataTable[] { + this.Messages}); + // + // Messages + // + this.Messages.Columns.AddRange(new System.Data.DataColumn[] { + this.levelColumn, + this.timeColumn, + this.messageColumn, + this.fullMessageColumn}); + this.Messages.TableName = "MessageTable"; + // + // levelColumn + // + this.levelColumn.Caption = ""; + this.levelColumn.ColumnName = "levelColumn"; + // + // timeColumn + // + this.timeColumn.Caption = ""; + this.timeColumn.ColumnName = "timeColumn"; + this.timeColumn.DataType = typeof(System.DateTime); + this.timeColumn.DateTimeMode = System.Data.DataSetDateTime.Local; + // + // messageColumn + // + this.messageColumn.ColumnName = "messageColumn"; + // + // fullMessageColumn + // + this.fullMessageColumn.ColumnName = "fullMessageColumn"; + // + // MessageWindow + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.Controls.Add(this.messagesDataGridView); + this.Controls.Add(this.messagesToolStrip); + this.Name = "MessageWindow"; + this.contextMenu.ResumeLayout(false); + this.messagesToolStrip.ResumeLayout(false); + this.messagesToolStrip.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.messagesDataGridView)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.messagesBindingSource)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.messageWindowData)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.Messages)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ImageList levelImages; + //Moved this one to main class so it can be precompiled + //private System.Windows.Forms.DataGridViewImageColumn Level; + private System.Windows.Forms.ContextMenuStrip contextMenu; + private System.Windows.Forms.ToolStripMenuItem buttonCopy; + private System.Windows.Forms.ToolStripSeparator cToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem buttonClearAll; + private System.Windows.Forms.BindingSource messagesBindingSource; + private System.Windows.Forms.ToolStrip messagesToolStrip; + private System.Windows.Forms.ToolStripButton buttonShowWarning; + private System.Windows.Forms.ToolStripButton buttonShowError; + private System.Windows.Forms.ToolStripButton buttonShowInfo; + private System.Windows.Forms.DataGridView messagesDataGridView; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private ToolStripButton buttonShowDetails; + private System.Data.DataSet messageWindowData; + private System.Data.DataTable Messages; + private System.Data.DataColumn levelColumn; + private System.Data.DataColumn timeColumn; + private System.Data.DataColumn messageColumn; + private System.Data.DataColumn fullMessageColumn; + private DataGridViewImageColumn levelColumnDataGridViewTextBoxColumn; + private DataGridViewTextBoxColumn timeColumnDataGridViewTextBoxColumn; + private DataGridViewTextBoxColumn messageColumnDataGridViewTextBoxColumn; + private DataGridViewTextBoxColumn fullMessageColumnDataGridViewTextBoxColumn; + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,390 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.IO; +using System.Windows.Forms; +using Core.Gui.Clipboard; +using Core.Gui.Properties; +using log4net.Core; + +namespace Core.Gui.Forms.MessageWindow +{ + /// + /// Class that receives messages from to be displayed + /// in a thread-safe way. This view supports filtering particular logging levels. + /// + public partial class MessageWindow : UserControl, IMessageWindow + { + private readonly IWin32Window dialogParent; + private readonly Dictionary levelImageName; + private readonly ConcurrentQueue newMessages = new ConcurrentQueue(); + private bool filtering; + + /// + /// Initializes a new instance of the class. + /// + /// The dialog parent for which dialogs should be shown on top. + public MessageWindow(IWin32Window dialogParent) + { + this.dialogParent = dialogParent; + + MessageWindowLogAppender.Instance.MessageWindow = this; + InitializeComponent(); + + // order is the same as in log4j Level (check sources of log4net) + levelImageName = new Dictionary + { + [Level.Off.ToString()] = errorLevelImageName, + [Level.Emergency.ToString()] = errorLevelImageName, + [Level.Fatal.ToString()] = errorLevelImageName, + [Level.Alert.ToString()] = errorLevelImageName, + [Level.Critical.ToString()] = errorLevelImageName, + [Level.Severe.ToString()] = errorLevelImageName, + [Level.Error.ToString()] = errorLevelImageName, + [Level.Warn.ToString()] = warningLevelImageName, + [Level.Notice.ToString()] = warningLevelImageName, + [Level.Info.ToString()] = informationLevelImageName, + [Level.Debug.ToString()] = debugLevelImageName, + [Level.Fine.ToString()] = debugLevelImageName, + [Level.Trace.ToString()] = debugLevelImageName, + [Level.Finer.ToString()] = debugLevelImageName, + [Level.Verbose.ToString()] = debugLevelImageName, + [Level.Finest.ToString()] = debugLevelImageName, + [Level.All.ToString()] = debugLevelImageName + }; + + messagesDataGridView.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText; + messagesDataGridView.MouseUp += MessagesDataGridViewMouseUp; + + ApplyFilter(); + messagesDataGridView.CellFormatting += MessagesDataGridViewCellFormatting; + + // fixes DPI problem + messagesDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; + messagesDataGridView.RowsAdded += MessagesDataGridViewRowsAdded; + } + + #region IView Members + + public object Data + { + get + { + return Messages; + } + set {} + } + + #endregion + + #region IMessageWindow Members + + public void AddMessage(Level level, DateTime time, string message) + { + if (level == null) + { + throw new ArgumentNullException(nameof(level)); + } + + string shortMessage; + using (var reader = new StringReader(message)) + { + shortMessage = reader.ReadLine(); + } + + newMessages.Enqueue(new MessageData + { + ImageName = level.ToString(), + Time = time, + ShortMessage = shortMessage, + FullMessage = message + }); + Invalidate(); + } + + #endregion + + private void PopulateMessages() + { + if (newMessages.IsEmpty) + { + return; + } + + Messages.BeginLoadData(); + + try + { + MessageData msg; + while (newMessages.TryDequeue(out msg)) + { + DataRow row = Messages.NewRow(); + + row[0] = msg.ImageName; + row[1] = msg.Time; + row[2] = msg.ShortMessage; + row[3] = msg.FullMessage; + + Messages.Rows.InsertAt(row, 0); + } + } + finally + { + Messages.EndLoadData(); + } + + if (messagesDataGridView.Rows.Count > 0) + { + messagesDataGridView.CurrentCell = messagesDataGridView.Rows[0].Cells[0]; + } + } + + private void AutoSizeRow(DataGridViewRow row) + { + int prefHeight = row.GetPreferredHeight(row.Index, DataGridViewAutoSizeRowMode.AllCells, false); + + if (prefHeight > 100) + { + row.Height = 100; + return; + } + + messagesDataGridView.AutoResizeRow(row.Index, DataGridViewAutoSizeRowMode.AllCells); + } + + private void ValidateContextMenuCommands() + { + foreach (ToolStripItem item in contextMenu.Items) + { + item.Enabled = messagesDataGridView.Rows.Count > 0; + } + } + + private void ApplyFilter() + { + filtering = true; + + messagesBindingSource.Filter = CreateLoggingLevelDataGridViewFilter(); + + filtering = false; + + foreach (DataGridViewRow row in messagesDataGridView.Rows) + { + AutoSizeRow(row); + } + } + + private string CreateLoggingLevelDataGridViewFilter() + { + var filterlines = new List(); + string filterFormat = string.Format(CultureInfo.CurrentCulture, + "{0} = '{{0}}'", + levelColumn.ColumnName); + if (buttonShowInfo.Checked) + { + filterlines.Add(string.Format(CultureInfo.CurrentCulture, + filterFormat, + Level.Info)); + } + + if (buttonShowWarning.Checked) + { + filterlines.Add(string.Format(CultureInfo.CurrentCulture, + filterFormat, + Level.Warn)); + } + + if (buttonShowError.Checked) + { + filterlines.Add(string.Format(CultureInfo.CurrentCulture, + filterFormat, + Level.Error)); + filterlines.Add(string.Format(CultureInfo.CurrentCulture, + filterFormat, + Level.Fatal)); + } + + return filterlines.Count == 0 + ? string.Format(CultureInfo.CurrentCulture, + filterFormat, + "NOTHING SHOWN") + : string.Join(" OR ", filterlines); + } + + private void ShowMessageWindowDialog() + { + if (messagesDataGridView.CurrentRow == null) + { + return; + } + + var messageWindowDialog = new MessageWindowDialog(dialogParent, (string) messagesDataGridView.CurrentRow.Cells[fullMessageColumnDataGridViewTextBoxColumn.Index].Value); + + messageWindowDialog.ShowDialog(); + } + + /// + /// Class that holds message information. + /// + private class MessageData + { + /// + /// Gets or sets the image representation of the logging level. + /// + public string ImageName { get; set; } + + /// + /// Gets or sets the time when the message was logged. + /// + public DateTime Time { get; set; } + + /// + /// Gets or sets the short message text, i.e., the first line of . + /// + public string ShortMessage { get; set; } + + /// + /// Gets or sets the full message text. + /// + public string FullMessage { get; set; } + } + + #region Events + + protected override void OnLoad(EventArgs e) + { + Text = Resources.MessageWindow_MessageWindow_Messages; + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + PopulateMessages(); + } + + #region Messages data grid view + + private void MessagesDataGridViewCellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) + { + if (e.Button == MouseButtons.Left && e.RowIndex > -1) + { + ShowMessageWindowDialog(); + } + } + + private void MessagesDataGridViewKeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + ShowMessageWindowDialog(); + + e.Handled = true; + } + } + + private void MessagesDataGridViewMouseUp(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Right) + { + ValidateContextMenuCommands(); + } + } + + private void MessagesDataGridViewRowsAdded(object sender, DataGridViewRowsAddedEventArgs e) + { + if (filtering) + { + return; + } + + DataGridViewRow row = messagesDataGridView.Rows[e.RowIndex]; + AutoSizeRow(row); + } + + private void MessagesDataGridViewCellFormatting(object sender, DataGridViewCellFormattingEventArgs e) + { + if (e.ColumnIndex != levelColumnDataGridViewTextBoxColumn.Index || e.Value == null) + { + return; + } + + // Dataset stores image-name instead of actual image, therefore we map to + // actual image during formatting. + var level = (string) e.Value; + e.Value = levelImages.Images[levelImageName[level]]; + } + + #endregion + + #region Button + + private void ButtonClearAllClick(object sender, EventArgs e) + { + Messages.Clear(); + } + + private void ButtonCopyClick(object sender, EventArgs e) + { + ClipboardProvider.Clipboard.SetDataObject(messagesDataGridView.GetClipboardContent()); + } + + private void ButtonShowDetailsClick(object sender, EventArgs e) + { + ShowMessageWindowDialog(); + } + + private void ButtonShowInfoClick(object sender, EventArgs e) + { + buttonShowInfo.Checked = !buttonShowInfo.Checked; + ApplyFilter(); + } + + private void ButtonShowWarningClick(object sender, EventArgs e) + { + buttonShowWarning.Checked = !buttonShowWarning.Checked; + ApplyFilter(); + } + + private void ButtonShowErrorClick(object sender, EventArgs e) + { + buttonShowError.Checked = !buttonShowError.Checked; + ApplyFilter(); + } + + #endregion + + #endregion + + #region Constants referring to the item-names of the ImageList + + private const string errorLevelImageName = "exclamation.png"; + private const string warningLevelImageName = "error.png"; + private const string informationLevelImageName = "information.png"; + private const string debugLevelImageName = "debug.png"; + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.resx (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindow.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 286, 21 + + + + 137, 22 + + + &Kopiëren + + + 134, 6 + + + 137, 22 + + + &Alles wissen + + + 138, 54 + + + contextMenu + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 175, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACo + EwAAAk1TRnQBSQFMAgEBBAEAAVgBAQFYAQEBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wAIAAFCAQkB/wEA + AToBAAH/JAADGQEjA0UBfQJaAV8B2wJMAXIB8wJMAXEB8wJaAV8B2wNFAX0DGQEjIAADGQEjA0UBfQJf + AV4B2wFwAV8BXQHzAW8BXwFdAfMCXwFeAdsDRQF9AxkBIxAAA1EBogEcAacB4AH/ARoBpAHfAf8BGAGh + Ad0B/wEWAZ4B3AH/ARQBmwHaAf8BEgGYAdkB/wEPAZMB1gH/AQoBjAHTAf8BBQGFAc8B/wEAAW0BzAH/ + AQABZgHJAf8BAAFgAcYB/wEAAVsBwwH/AQABVwHBAf8DUQGiIAABCQFLAQkB/wEAAUIBCQH/AQABQgEJ + Af8gAAMzAVMCWAFkAeYBQQFTAdQB/wGEAZAB5wH/AZUBoAHuAf8BlQGfAe0B/wGDAY4B5QH/ATsBTAHO + Af8CWAFiAeYDMwFTGAADMwFTAWICYQHmAdoBqAFuAf8B/QHfAbsC/wHrAc4C/wHrAc4B/wH6AdwBuAH/ + AdMBogFpAf8DYQHmAzMBUwwAAVgCXwHjAb4B4wH1Af8B9AH8Af4B/wHvAfsB/gH/Ae4B+wH+Af8B7gH7 + Af4B/wHvAfwB/gH/Ae8B/AH+Af8B7wH7Af4B/wHuAfsB/gH/Ae0B+wH+Af8B7QH7Af4B/wHsAfsB/gH/ + AfIB/AH+Af8BqwHOAesB/wFaAl4B2BQAAREBgQERAf8BCQFTAREB/wEJAVMBCQH/AQkBSwEJAf8BCQFL + AQkB/yAAAzMBUwJSAXkB9AFkAYQB4wH/AaEBrAH0Af8BbgGLAewB/wFLAVYB5AH/AUoBVQHjAf8BbAGH + AeoB/wGfAagB8QH/AV4BawHdAf8BSgFSAXUB9AMzAVMQAAMzAVMBdwFlAVIB9AHzAc8BpQL/AeMBxwH/ + AesBxAGfAf8B3gGyAYoB/wHcAa4BiAH/AeYBvgGaAf8B+QHbAb8B/wHtAcsBnwH/AXABZQFdAfQDMwFT + CAADMAFLAVEBvwHoAf8B9AH8Af4B/wG1Ae8B+gH/AUcB2gH1Af8BRwHaAfUB/wFGAdgB8wH/AUcB1wHy + Af8BRwHWAfIB/wFGAdkB9AH/AUAB2AH1Af8BPQHXAfQB/wFRAdoB9gH/AeoB+wH+Af8BMwGTAdIB/wMw + AUsQAAERAYEBEQH/AREBgQERAf8BUwGlAYEB/wFTAaUBgQH/AREBgQERAf8BCQFLAQkB/wEJAVMBEQH/ + AQkBSwEJAf8BAAFCAQkB/wEAAUIBCQH/AQABQgEJAf8IAAMYASICXgFlAeUBZwGIAeYB/wGjAbAB9QH/ + AUYBVgHnAf8BRQFUAeYB/wGJAZIB7QH/AYgBkgHsAf8BQgFOAeIB/wFBAUwB4QH/AZ8BqQHyAf8BXgFs + Ad0B/wJeAWUB5QMYASIIAAMYASICZQFeAeUB9wHSAakC/wHkAcoB/wHmAbkBjgH/AeIBtAGKAf8B3wGx + AYcB/wHbAawBhgH/AdkBqwGFAf8B2AGrAYQB/wH1AdIBtQH/Ae4BzQGhAf8CZQFeAeUDGAEiCAABWgJd + AcoBnQHXAfEB/wHnAfkB/QH/AYsB5QH4Af8BSQHbAfYB/wFKAdoB9AH/ASwBoQHVAf8BLAGhAdUB/wFD + AdYB8gH/AUEB2AH1Af8BPwHWAfQB/wHYAfYB/AH/AYgBvwHlAf8BVQJWAbQQAAERAYQBGQH/AQkBgQEJ + Af8BlAHGAZwB/wFTAa0BhAH/ATIBnAFLAf8BUwGtAYQB/wGBAaUBgQH/AQkBUwEJAf8BCQFTAREB/wEJ + AUsBCQH/AQkBSwEJAf8MAANGAX4BTwFiAeAB/wGkAbMB9wH/AUkBXQHrAf8BSAFbAeoB/wFHAVgB6An/ + AUQBUQHlAf8BQwFQAeMB/wFCAU4B4gH/AZ8BqQHyAf8BPwFQAdEB/wFFAkYBfggAA0YBfgHnAbkBhgL/ + AeoB0AH/Ae0BvgGUAf8B6gG5AZEC/wHzAeAL/wH4Af8B3AGtAYYB/wHbAa0BhgH/AfwB3QHBAf8B1gGj + AW0B/wNGAX4IAAMaASQBMgGOAaMB+wHzAfsB/gH/AcMB8gH7Af8BSwHcAfYB/wFLAdoB9AH/AVMB3wH2 + Af8BRgHLAesB/wFEAdYB8gH/AUMB2QH1Af8BlAHnAfgB/wHjAfQB+wH/ATEBagGOAfkDGgEkDAABGQGU + ASEB/wERAYwBGQH/AYEBtQGEAf8BMgGcAToB/wGBAbUBjAH/ATIBpQFTAf8BMgGcAUsB/wFTAa0BhAH/ + ARkBgQEhAf8BCQFTAQkB/wEJAVMBEQH/EAABWgJfAdsBjgGfAfAB/wGEAZkB9AH/AUsBYgHuAf8BSgFf + AewB/wFJAV0B6wH/AZABnQHxAf8BpgGvAfMB/wFGAVYB5wH/AUUBVAHmAf8BRAFRAeUB/wFsAYkB6wH/ + AYUBkQHnAf8CWgFfAdsIAAJfAV4B2wH/AeQBxAH/Af0B1QGxAf8B7wHAAZQB/wHrAb0BkQH/AekBuwGP + A/8B+wX/AeMBswGLAf8B4QGyAYsB/wHgAbIBigH/Ae0BxQGgAf8B+gHgAbsB/wJfAV4B2wwAA1MBqgGM + AdIB8AH/AeoB+wH+Af8BlAHmAfgB/wFLAdoB9AH/ATYBsQHdAf8BLAGhAdUB/wFFAdcB8gH/AUsB2wH1 + Af8B3gH4Af0B/wFsAcAB5wH/AUgCSQGHEAABGQGUASEB/wFLAa0BUwH/AYEBvQGUAf8BKgGlAUIB/wEy + AZwBOgH/AYEBtQGMAf8BMgGlAVMB/wEyAZwBSwH/AVMBrQGEAf8BUwGlAVMB/wEJAVMBEQH/AQkBUwER + Af8EAAEJAUsBCQH/BAABVwFiAYEB9gGgAbMB9wH/AVQBgAHyAf8BTgFnAfAB/wFMAWUB7wH/AUsBYgHu + Af8B0wHZAfoF/wFIAVsB6gH/AUcBWAHoAf8BRgFWAecB/wFMAVsB5wH/AZkBpQHxAf8BSAFJAXkB9ggA + AYEBbgFdAfYB/wHvAdcB/wH4AcoBngH/Ae0BwQGTAf8B7AG/AZIB/wHsAb4BkQP/AfwF/wHnAbgBjgH/ + AeYBtwGNAf8B5gG3AYwB/wHmAboBkQL/Ae4B0gH/AXUBYgFcAfYMAAMJAQwBWQFkAWoB7AHIAeoB9wH/ + AeYB+gH9Af8BTAHaAfQB/wEsAaEB1QH/ASwBoQHVAf8BRgHXAfIB/wHHAfMB/AH/AcAB4wH0Af8BWgJh + AeQDCQEMEAABGQGcASEB/wE6Aa0BQgH/AVMBvQGMAf8BMgGlAVMB/wEqAZwBQgH/ATIBpQE6Af8BhAG9 + AZwB/wE6AaUBUwH/ATIBnAFLAf8BhAG9AZwB/wERAYEBEQH/AQkBgQERAf8BCQFTAREB/wEJAVMBCQH/ + BAABWwFiAYUB9gGhAbYB+AH/AVYBhAH0Af8BTwFrAfMB/wFOAWkB8QH/AU4BZwHwCf8BSgFfAewB/wFJ + AV0B6wH/AUgBWwHqAf8BTgFeAekB/wGbAagB8QH/AUgBSQF7AfYIAAGFAXEBYgH2Af8B8QHYAf8B+AHL + AaIB/wH0AcUBmQH/Ae8BwgGUAf8B7QHAAZMJ/wHrAb4BkQH/AekBvAGQAf8B6gG8AZAB/wHrAcABlQL/ + Ae0B0wH/AXcBYgFcAfYQAAM3AVoBYAHIAe0B/wH5Af4C/wFNAdwB9AH/AS0BogHVAf8BLQGiAdUB/wFL + AdkB9AH/Ae0B+wH+Af8BVwG7AeUB/wM3AVoQAAEZAaUBIQH/ARkBpQEhAf8BGQGcASEB/wGUAc4BrQH/ + AUIBtQGBAf8BOgGtAYEB/wEqAZwBQgH/ATIBpQE6Af8BhAG9AZwB/wE6AaUBUwH/AYwBvQGcAf8BEQGB + AREB/wERAYEBEQH/AQkBgQERAf8IAANfAdsBkQGmAfMB/wGIAaEB+AH/AVEBgAH0Af8BUAFtAfMB/wFP + AWsB8wn/AUwBZQHvAf8BSwFiAe4B/wFKAV8B7AH/AYIBkwHxAf8BiQGYAewB/wJaAV8B2wgAA18B2wH/ + AeQBxwL/AdsBuwH/AfcByAGdAf8B9QHGAZoB/wHzAcQBmQL/AecBywL/AecBygH/Ae0BwQGTAf8B7QHB + AZMB/wHsAcABkwH/AfkB0wGtAv8B4gG/Af8CXwFeAdsUAAFcAmAB1AGpAd8B9AH/Ae0B+QH9Af8BLQGj + AdYB/wEtAaMB1gH/AdQB9QH8Af8BogHXAfEB/wFZAlsBwxAAASEBrQEhAf8BGQGlASEB/wEZAaUBIQH/ + ASEBpQEhAf8BOgGtAUIB/wGMAc4BpQH/AUIBtQGEAf8BOgGtAYEB/wEqAaUBQgH/AToBrQFCAf8BnAHO + Aa0B/wGMAb0BlAH/AREBhAERAf8BCQFCASEB/wwAA0YBfgFbAYEB7AH/AakBvQH7Af8BUgGCAfUB/wFR + AYEB9QH/AVEBgAH0Cf8BTgFpAfEB/wFOAWcB8AH/AUwBZQHvAf8BpQG1AfgB/wFMAV8B3QH/AUUCRgF+ + CAADRgF+AfUBxAGQAv8B8wHcAf8B/AHNAaIB/wH4AcgBnwH/AfcBxgGcCf8B8wHGAZkB/wHzAcUBmQH/ + AfUByQGfAv8B6AHNAf8B4QGyAYMB/wNGAX4UAAMhATABQAGoAbwB/QH5Af0C/wGUAekB+QH/AZ4B6wH6 + Af8B7AH6Af4B/wErAXwBsAH8AyEBMBAAASEBtQEqAf8BIQGtASEB/wgAARkBpQEhAf8BIQGlASEB/wGU + Ac4BrQH/AUsBvQGEAf8BOgGtAYEB/wFCAbUBgQH/ASEBlAEhAf8BEQGMARkB/wE6AaUBSwH/AQkBOgEq + Af8MAAMYASIDZQHlAYMBlwHwAf8BqQG9AfsB/wFSAYIB9QH/AVIBggH1Cf8BUAFtAfMB/wFPAWsB8wH/ + AaYBuQH5Af8BagGNAeoB/wFeAWQBZQHlAxgBIggAAxgBIgNlAeUB/wHaAbQC/wHyAdsC/wHRAaUB/wH5 + Ac0BoQL/AewB0AL/AesB0AH/AfgBygGeAf8B+QHMAZ8C/wHlAcoB/wH4AdQBrQH/AmUBXgHlAxgBIhgA + AVUCVgG0AZQB2AHyAf8B8wH8Af4B/wHnAfoB/gH/AY8B0wHwAf8BTQJOAZYgAAEhAa0BIQH/ARkBrQEh + Af8BIQGlASEB/wEqAa0BMgH/AZwB1gGtAf8BpQHWAb0B/wGEAcYBjAH/AREBjAERAf8BMgG1AUIB/wGc + Ac4BrQH/AREBjAEZAf8BEQGEAREB/wERAYQBGQH/CAADMwFTAmUBfwH0AYQBlwHxAf8BqQG9AfsB/wGK + AaMB+AH/AVoBiQH2Af8BWgGJAfYB/wGJAaIB+AH/AagBvAH6Af8BbgGSAewB/wFSAWUBfQH0AzMBUxAA + AzMBUwF/AXMBZQH0Af8B2gG0Av8B9QHgAv8B4gHFAv8B0wGtAv8B0QGqAv8B2wG5Av8B6gHTAf8B/AHW + Aa4B/wF7AWUBXQH0AzMBUxwAAw0BEgFXAXIBewHyAfEB+gH9Af8B1QHvAfoB/wFaAWYBagHtAw0BEiAA + ASEBtQEqAf8BIQGtASEB/wQAASEBrQEhAf8BGQGlASEB/wEhAaUBIQH/ARkBpQEhAf8BgQHGAYEB/wGt + AecBxgH/AUIBjAGBAf8BGQFLATIB/xQAAzMBUwJhAWYB5gFdAYMB7gH/AZIBpgH0Af8BoAG0AfgB/wGg + AbQB+AH/AZEBpgHzAf8BVwFsAekB/wFaAWEBZgHmAzMBUxgAAzMBUwFmAWIBYQHmAfgByAGSAv8B5wHI + Av8B7QHWAv8B7QHWAv8B5AHHAf8B8AG/AYoB/wFmAmEB5gMzAVMkAAFNAk4BlQGFAdQB8QH/AYIB0QHw + Af8DPQFpJAABIQG1ASoB/wEhAbUBIQH/CAABIQGtASEB/wEZAaUBIQH/ASoBgQFLAf8BIQGEAToB/wEZ + AZwBIQH/ASEBgQFCAf8cAAMZASMDRQF9A18B2wFfAWABgAHzAl8BgAHzA18B2wNFAX0DGQEjIAADGQEj + A0UBfQNfAdsBgAFwAV8B8wF/AXABXwHzA18B2wNFAX0DGQEjKAADAgEDAVwCYAHUAVkCWwHDAwIBAyQA + ASEBvQEqAf8MAAEhAbUBKgH/ASEBrQEhAf8BMgGMAVMB/wEhAaUBIQH/ARkBpQEhAf/sAAEhAbUBKgH/ + ASEBtQEhAf8EAAEhAa0BIQH/ARkBrQEhAf8QAAFCAU0BPgcAAT4DAAEoAwABQAMAASADAAEBAQABAQYA + AQEWAAP/gQAH/wGfAfABDwHwAQ8CAAH/AR8B4AEHAeABBwIAAfgBPwHAAQMBwAEDAgAB8AEBAYABAQGA + AQEBgAEBAeABAwGAAQEBgAEBAYABAQHAAQcBgAEBAYABAQHAAQMBwAECAYABAQGAAQEBwAEDAcABAAGA + AQEBgAEBAeABBwGAAQEBgAEBAYABAQHwAQ8BAAEDAYABAQGAAQEB8AEPATABAwGAAQEBgAEBAfgBHwHg + AQABwAEDAcABAwH4AR8B5AEDAeABBwHgAQcB/AE/AeYBBwHwAQ8B8AEPAfwBPwHuAQ8G/wH+AU8L + + + + 671, 17 + + + + None + + + Magenta + + + 23, 22 + + + Toon Informatieberichten + + + Toon informatieberichten + + + Magenta + + + 23, 22 + + + Laat Waarschuwingsberichten zien + + + Toon waarschuwingen + + + Magenta + + + 23, 22 + + + Laat foutberichten zien + + + Toon fouten + + + 6, 25 + + + Magenta + + + 23, 22 + + + buttonShowDetails + + + Toon details van het actieve bericht + + + 0, 0 + + + 647, 25 + + + + 5 + + + toolStrip2 + + + messagesToolStrip + + + System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + + + + 20 + + + Tijd + + + 49 + + + Bericht + + + True + + + fullMessageColumn + + + False + + + 401, 17 + + + 40, 17 + + + Fill + + + 0, 25 + + + 2, 2, 2, 2 + + + 647, 337 + + + 6 + + + messagesDataGridView + + + System.Windows.Forms.DataGridView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + 96, 96 + + + True + + + 2, 2, 2, 2 + + + 647, 362 + + + buttonCopy + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + cToolStripMenuItem + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + buttonClearAll + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + levelImages + + + System.Windows.Forms.ImageList, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + buttonShowInfo + + + System.Windows.Forms.ToolStripButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + buttonShowWarning + + + System.Windows.Forms.ToolStripButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + buttonShowError + + + System.Windows.Forms.ToolStripButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator1 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + buttonShowDetails + + + System.Windows.Forms.ToolStripButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + levelColumnDataGridViewTextBoxColumn + + + System.Windows.Forms.DataGridViewImageColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + timeColumnDataGridViewTextBoxColumn + + + System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + messageColumnDataGridViewTextBoxColumn + + + System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + fullMessageColumnDataGridViewTextBoxColumn + + + System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + messagesBindingSource + + + System.Windows.Forms.BindingSource, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + messageWindowData + + + System.Data.DataSet, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Messages + + + System.Data.DataTable, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + levelColumn + + + System.Data.DataColumn, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + timeColumn + + + System.Data.DataColumn, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + messageColumn + + + System.Data.DataColumn, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + fullMessageColumn + + + System.Data.DataColumn, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + MessageWindow + + + System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,87 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms.MessageWindow +{ + partial class MessageWindowDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 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(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MessageWindowDialog)); + this.textBox = new System.Windows.Forms.TextBox(); + this.buttonHidden = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // textBox + // + resources.ApplyResources(this.textBox, "textBox"); + this.textBox.Name = "textBox"; + this.textBox.ReadOnly = true; + this.textBox.TabStop = false; + // + // buttonHidden + // + resources.ApplyResources(this.buttonHidden, "buttonHidden"); + this.buttonHidden.Name = "buttonHidden"; + this.buttonHidden.UseVisualStyleBackColor = true; + // + // MessageWindowDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.textBox); + this.Controls.Add(this.buttonHidden); + this.Name = "MessageWindowDialog"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox; + private System.Windows.Forms.Button buttonHidden; + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,50 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; +using Core.Common.Controls.Dialogs; +using Core.Gui.Properties; + +namespace Core.Gui.Forms.MessageWindow +{ + /// + /// Dialog for showing a particular message. + /// + public partial class MessageWindowDialog : DialogBase + { + /// + /// Constructs a new . + /// + /// The owner of the dialog, for which this should show on top. + /// The text to show in the dialog. + public MessageWindowDialog(IWin32Window dialogParent, string text) : base(dialogParent, Resources.application_import_blue1, 200, 150) + { + InitializeComponent(); + + textBox.Text = text; + } + + protected override Button GetCancelButton() + { + return buttonHidden; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.resx (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowDialog.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Bottom, Left, Right + + + + Courier New, 8.25pt + + + 12, 12 + + + + True + + + Both + + + 700, 238 + + + 0 + + + textBox + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + 25, 25 + + + 0, 0 + + + 1 + + + buttonHidden + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + 6, 13 + + + 724, 262 + + + Berichtdetails + + + MessageWindowDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowLogAppender.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowLogAppender.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/MessageWindow/MessageWindowLogAppender.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,172 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using Core.Common.Util.Reflection; +using Core.Gui.Properties; +using log4net.Appender; +using log4net.Core; +using log4net.Util; + +namespace Core.Gui.Forms.MessageWindow +{ + /// + /// A log-appender for Log4Net that is able to forward received messages to a + /// instance. + /// + public class MessageWindowLogAppender : AppenderSkeleton + { + /// + /// This list contains any messages that could not yet be delivered to the + /// (typically because it doesn't exist yet at startup). The messages are kept in the backlog + /// and sent to upon the next message arriving while an + /// instance of has been set. + /// + private readonly List messageBackLog = new List(); + + private bool enabled; + private IMessageWindow messageWindow; + + /// + /// Initializes a new instance of the class and + /// the singleton instance. + /// + public MessageWindowLogAppender() + { + Instance = this; + } + + /// + /// Gets the singleton instance. + /// + public static MessageWindowLogAppender Instance { get; set; } + + /// + /// Gets or sets the message window to which log-messages should be forwarded. + /// + public IMessageWindow MessageWindow + { + get + { + return messageWindow; + } + set + { + messageWindow = value; + FlushMessagesToMessageWindow(); + } + } + + /// + /// Gets or sets a value indicating whether or not this appender should forward its + /// messages to (set to true) or should cache + /// them for when it's enabled at a later time (set to false). + /// + public bool Enabled + { + get + { + return enabled; + } + set + { + enabled = value; + FlushMessagesToMessageWindow(); + } + } + + protected override void Append(LoggingEvent loggingEvent) + { + if (MessageWindow == null || !enabled) + { + messageBackLog.Add(loggingEvent); + } + else + { + FlushMessagesToMessageWindow(); + AppendToMessageWindow(loggingEvent); + } + } + + private void AppendToMessageWindow(LoggingEvent loggingEvent) + { + string message = null; + + var stringFormat = loggingEvent.MessageObject as SystemStringFormat; + if (stringFormat != null) + { + var format = TypeUtils.GetField(stringFormat, "m_format"); + var args = TypeUtils.GetField(stringFormat, "m_args"); + message = GetLocalizedMessage(format, args); + } + + if (message == null) + { + message = loggingEvent.RenderedMessage; + } + + if (loggingEvent.ExceptionObject != null) + { + message += @" " + Environment.NewLine + Resources.MessageWindowLogAppender_AppendToMessageWindow_Check_log_file_for_more_information_Home_Show_Log; + } + + MessageWindow.AddMessage(loggingEvent.Level, loggingEvent.TimeStamp, message); + } + + private void FlushMessagesToMessageWindow() + { + if (messageWindow == null || !enabled) + { + return; + } + + if (messageBackLog.Count > 0) + { + foreach (LoggingEvent backLogLoggingEvent in messageBackLog.ToArray()) + { + AppendToMessageWindow(backLogLoggingEvent); + } + + messageBackLog.Clear(); + } + } + + private static string GetLocalizedMessage(string format, object[] args) + { + try + { + return string.Format(CultureInfo.CurrentCulture, + format, + args); + } + catch (ArgumentNullException) + { + return format; + } + catch (FormatException) + { + return format; + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,126 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms.ProgressDialog +{ + partial class ActivityProgressDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ActivityProgressDialog)); + this.progressBar = new System.Windows.Forms.ProgressBar(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.labelActivityCounter = new System.Windows.Forms.Label(); + this.labelActivityDescription = new System.Windows.Forms.Label(); + this.pictureBoxActivityDescription = new System.Windows.Forms.PictureBox(); + this.pictureBoxActivityProgressText = new System.Windows.Forms.PictureBox(); + this.labelActivityProgressText = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxActivityDescription)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxActivityProgressText)).BeginInit(); + this.SuspendLayout(); + // + // progressBar + // + resources.ApplyResources(this.progressBar, "progressBar"); + this.progressBar.MarqueeAnimationSpeed = 0; + this.progressBar.Name = "progressBar"; + this.progressBar.Style = System.Windows.Forms.ProgressBarStyle.Continuous; + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.ButtonCancelClick); + // + // labelActivityCounter + // + resources.ApplyResources(this.labelActivityCounter, "labelActivityCounter"); + this.labelActivityCounter.Name = "labelActivityCounter"; + // + // labelActivityDescription + // + this.labelActivityDescription.AutoEllipsis = true; + resources.ApplyResources(this.labelActivityDescription, "labelActivityDescription"); + this.labelActivityDescription.Name = "labelActivityDescription"; + // + // pictureBoxActivityDescription + // + this.pictureBoxActivityDescription.Image = global::Core.Gui.Properties.Resources.Busy_indicator; + resources.ApplyResources(this.pictureBoxActivityDescription, "pictureBoxActivityDescription"); + this.pictureBoxActivityDescription.Name = "pictureBoxActivityDescription"; + this.pictureBoxActivityDescription.TabStop = false; + // + // pictureBoxActivityProgressText + // + this.pictureBoxActivityProgressText.Image = global::Core.Gui.Properties.Resources.arrow_000_medium; + resources.ApplyResources(this.pictureBoxActivityProgressText, "pictureBoxActivityProgressText"); + this.pictureBoxActivityProgressText.Name = "pictureBoxActivityProgressText"; + this.pictureBoxActivityProgressText.TabStop = false; + // + // labelActivityProgressText + // + this.labelActivityProgressText.AutoEllipsis = true; + resources.ApplyResources(this.labelActivityProgressText, "labelActivityProgressText"); + this.labelActivityProgressText.Name = "labelActivityProgressText"; + // + // ActivityProgressDialog + // + resources.ApplyResources(this, "$this"); + this.Controls.Add(this.labelActivityProgressText); + this.Controls.Add(this.pictureBoxActivityProgressText); + this.Controls.Add(this.pictureBoxActivityDescription); + this.Controls.Add(this.labelActivityDescription); + this.Controls.Add(this.labelActivityCounter); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.progressBar); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Name = "ActivityProgressDialog"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ActivityProgressDialogFormClosing); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxActivityDescription)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxActivityProgressText)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ProgressBar progressBar; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Label labelActivityCounter; + private System.Windows.Forms.Label labelActivityDescription; + private System.Windows.Forms.PictureBox pictureBoxActivityDescription; + private System.Windows.Forms.PictureBox pictureBoxActivityProgressText; + private System.Windows.Forms.Label labelActivityProgressText; + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,281 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Core.Common.Base.Service; +using Core.Common.Controls.Dialogs; +using Core.Gui.Properties; + +namespace Core.Gui.Forms.ProgressDialog +{ + /// + /// Dialog that runs a sequence of activities, showing their progress during the execution, + /// when shown. + /// + public partial class ActivityProgressDialog : DialogBase + { + private readonly IEnumerable activities; + private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); + private Task task; + private Activity runningActivity; + + /// + /// Method prototype for updating the progress step visualization user controls. + /// + /// The current step number. + /// The total number of activities. + private delegate void UpdateActivityStepControlsDelegate(int stepNumberForProgressNotification, int activityCount); + + /// + /// Method prototype for updating the progress bar control. + /// + /// The new progress bar value. + private delegate void UpdateProgressBarDelegate(int progressBarValue); + + /// + /// Method prototype for calling and closing this dialog. + /// + private delegate void FinishActivitiesAndCloseDialogDelegate(); + + /// + /// Method prototype for updating controls visualizing the progress of the activities. + /// + /// The activity currently raising . + private delegate void UpdateProgressControlsDelegate(Activity activity); + + /// + /// Initializes a new instance of the class. + /// + /// The dialog parent for which this dialog should be shown on top. + /// The activities to be executed when the dialog is shown. + public ActivityProgressDialog(IWin32Window dialogParent, IEnumerable activities) : base(dialogParent, Resources.Riskeer, 520, 150) + { + InitializeComponent(); + + this.activities = activities ?? Enumerable.Empty(); + } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + int activityCount = activities.Count(); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + task = RunAllActivitiesAsTask(activityCount, cancellationToken); + + FinishAllActivitiesInThreadSafeManner(); + } + + protected override Button GetCancelButton() + { + return buttonCancel; + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Escape) + { + CancelRunningActivities(); + return true; + } + + return base.ProcessCmdKey(ref msg, keyData); + } + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) + { + components?.Dispose(); + task?.Dispose(); + } + + cancellationTokenSource.Dispose(); + + base.Dispose(disposing); + } + + private Task RunAllActivitiesAsTask(int activityCount, CancellationToken cancellationToken) + { + return Task.Factory.StartNew(() => RunAllActivities(activityCount, cancellationToken), cancellationToken); + } + + private void RunAllActivities(int activityCount, CancellationToken cancellationToken) + { + for (var i = 0; i < activityCount; i++) + { + if (cancellationToken.IsCancellationRequested) + { + break; + } + + runningActivity = activities.ElementAt(i); + int stepNumberForProgressNotification = i + 1; + + RunActivity(stepNumberForProgressNotification, activityCount); + } + } + + private void RunActivity(int stepNumberForProgressNotification, int activityCount) + { + if (InvokeRequired) + { + UpdateActivityStepControlsDelegate updateDelegate = UpdateProgressControls; + Invoke(updateDelegate, stepNumberForProgressNotification, activityCount); + } + else + { + UpdateProgressControls(stepNumberForProgressNotification, activityCount); + } + + try + { + runningActivity.ProgressChanged += ActivityOnProgressChanged; + + runningActivity.Run(); + runningActivity.LogState(); + } + finally + { + runningActivity.ProgressChanged -= ActivityOnProgressChanged; + } + + UpdateProgressBar(stepNumberForProgressNotification, activityCount); + } + + private void FinishAllActivitiesInThreadSafeManner() + { + task.ContinueWith(t => + { + if (InvokeRequired) + { + FinishActivitiesAndCloseDialogDelegate wrappingUpDelegate = FinishAllActivitiesAndCloseDialog; + Invoke(wrappingUpDelegate); + } + else + { + FinishAllActivitiesAndCloseDialog(); + } + }, CancellationToken.None); + } + + private void FinishAllActivitiesAndCloseDialog() + { + foreach (Activity activity in activities) + { + activity.Finish(); + } + + Close(); + } + + private void ActivityProgressDialogFormClosing(object sender, FormClosingEventArgs e) + { + if (task != null && task.Status == TaskStatus.Running) + { + CancelRunningActivities(); + + e.Cancel = true; + } + } + + private void ButtonCancelClick(object sender, EventArgs e) + { + CancelRunningActivities(); + } + + private void CancelRunningActivities() + { + cancellationTokenSource.Cancel(); + runningActivity.Cancel(); + + labelActivityCounter.Text = Resources.ActivityProgressDialog_CancelActivities_Quit_after_finishing_current_activity; + } + + private void UpdateProgressBar(int stepNumberForProgressNotification, int activityCount) + { + var progressBarValue = (int) Math.Round(100.0 / activityCount * stepNumberForProgressNotification); + if (InvokeRequired) + { + UpdateProgressBarDelegate updateDelegate = UpdateProgressBar; + Invoke(updateDelegate, progressBarValue); + } + else + { + UpdateProgressBar(progressBarValue); + } + } + + private void UpdateProgressBar(int progressBarValue) + { + progressBar.Value = progressBarValue; + } + + private void ActivityOnProgressChanged(object sender, EventArgs e) + { + var activity = sender as Activity; + if (activity == null) + { + return; + } + + if (InvokeRequired) + { + UpdateProgressControlsDelegate updateDelegate = UpdateProgressControls; + Invoke(updateDelegate, activity); + } + else + { + UpdateProgressControls(activity); + } + } + + private void UpdateProgressControls(int stepNumberForProgressNotification, int activityCount) + { + labelActivityDescription.Text = runningActivity.Description; + pictureBoxActivityProgressText.Visible = false; + labelActivityProgressText.Visible = false; + labelActivityCounter.Text = string.Format(CultureInfo.CurrentCulture, + Resources.ActivityProgressDialog_OnShown_Executing_step_0_of_1, + stepNumberForProgressNotification, activityCount); + } + + private void UpdateProgressControls(Activity activity) + { + bool progressTextNullOrEmpty = string.IsNullOrEmpty(activity.ProgressText); + + pictureBoxActivityProgressText.Visible = !progressTextNullOrEmpty; + labelActivityProgressText.Visible = !progressTextNullOrEmpty; + labelActivityProgressText.Text = progressTextNullOrEmpty ? string.Empty : activity.ProgressText; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.resx (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialog.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 12, 79 + + + 391, 23 + + + + 0 + + + progressBar + + + System.Windows.Forms.ProgressBar, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + 416, 79 + + + 75, 23 + + + 1 + + + Annuleren + + + buttonCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + True + + + 13, 60 + + + 68, 13 + + + 2 + + + Stap 1 van 1 + + + labelActivityCounter + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + 36, 11 + + + 455, 13 + + + 3 + + + Uitvoeren taak + + + labelActivityDescription + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + 16, 9 + + + 16, 16 + + + 4 + + + pictureBoxActivityDescription + + + System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + 39, 29 + + + 16, 16 + + + 5 + + + pictureBoxActivityProgressText + + + System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + 61, 31 + + + 430, 13 + + + 6 + + + Stap 1 van 10 | Subtaak + + + labelActivityProgressText + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 504, 112 + + + Voortgang + + + ActivityProgressDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialogRunner.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialogRunner.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProgressDialog/ActivityProgressDialogRunner.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,61 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Collections.Generic; +using System.Windows.Forms; +using Core.Common.Base.Service; + +namespace Core.Gui.Forms.ProgressDialog +{ + /// + /// Helper methods for running a sequence of activities and observe their progress in a dialog. + /// + public static class ActivityProgressDialogRunner + { + /// + /// Runs a given activity while showing progress in a dialog. + /// + /// The dialog parent for which the progress dialog should be shown on top. + /// The activity to be executed. + public static void Run(IWin32Window dialogParent, Activity activity) + { + Run(dialogParent, new[] + { + activity + }); + } + + /// + /// Runs a sequence of activities of type while showing progress in a dialog. + /// + /// The activity type. + /// The dialog parent for which the progress dialog should be shown on top. + /// The activities to be executed. + public static void Run(IWin32Window dialogParent, IEnumerable activities) + where TActivity : Activity + { + using (var activityProgressDialog = new ActivityProgressDialog(dialogParent, activities)) + { + activityProgressDialog.ShowDialog(); + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ProjectExplorer/IProjectExplorer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProjectExplorer/IProjectExplorer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProjectExplorer/IProjectExplorer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,31 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Base.Data; +using Core.Common.Controls.Views; + +namespace Core.Gui.Forms.ProjectExplorer +{ + /// + /// View to show the contents of a instance. + /// + public interface IProjectExplorer : ISelectionProvider, IView {} +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,87 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms.ProjectExplorer +{ + partial class ProjectExplorer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 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(); + } + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProjectExplorer)); + this.treeViewPanel = new System.Windows.Forms.Panel(); + this.treeViewControl = new Core.Common.Controls.TreeView.TreeViewControl(); + this.treeViewPanel.SuspendLayout(); + this.SuspendLayout(); + // + // treeViewPanel + // + this.treeViewPanel.Controls.Add(this.treeViewControl); + resources.ApplyResources(this.treeViewPanel, "treeViewPanel"); + this.treeViewPanel.Name = "treeViewPanel"; + // + // treeViewControl + // + resources.ApplyResources(this.treeViewControl, "treeViewControl"); + this.treeViewControl.Name = "treeViewControl"; + // + // ProjectExplorer + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.treeViewPanel); + this.Name = "ProjectExplorer"; + this.treeViewPanel.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel treeViewPanel; + private Common.Controls.TreeView.TreeViewControl treeViewControl; + } +} Index: Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,120 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; +using Core.Common.Controls.TreeView; +using Core.Common.Util.Events; +using Core.Gui.Commands; +using Core.Gui.Properties; + +namespace Core.Gui.Forms.ProjectExplorer +{ + /// + /// This class describes a Project Explorer, which can be used to navigate and open views for elements + /// in the project. + /// + public sealed partial class ProjectExplorer : UserControl, IProjectExplorer + { + private readonly IViewCommands viewCommands; + + public event EventHandler SelectionChanged; + + /// + /// Creates a new instance of . + /// + /// The provider of view related commands. + /// The of which + /// are used to draw nodes. + /// Thrown when either: + /// + /// is null, + /// is null + /// + /// + public ProjectExplorer(IViewCommands viewCommands, IEnumerable treeNodeInfos) + { + if (viewCommands == null) + { + throw new ArgumentNullException(nameof(viewCommands)); + } + + if (treeNodeInfos == null) + { + throw new ArgumentNullException(nameof(treeNodeInfos)); + } + + InitializeComponent(); + + Text = Resources.ProjectExplorer_DisplayName; + + this.viewCommands = viewCommands; + + RegisterTreeNodeInfos(treeNodeInfos); + BindTreeInteractionEvents(); + } + + public object Data + { + get => treeViewControl.Data; + set + { + if (!IsDisposed) + { + treeViewControl.Data = value; + } + } + } + + public object Selection => treeViewControl.SelectedData; + + private void BindTreeInteractionEvents() + { + treeViewControl.DataDoubleClick += TreeViewControlDataDoubleClick; + treeViewControl.DataDeleted += TreeViewControlDataDeleted; + treeViewControl.SelectedDataChanged += TreeViewControlSelectedDataChanged; + } + + private void RegisterTreeNodeInfos(IEnumerable treeNodeInfos) + { + foreach (TreeNodeInfo info in treeNodeInfos) + { + treeViewControl.RegisterTreeNodeInfo(info); + } + } + + private void TreeViewControlSelectedDataChanged(object sender, EventArgs e) + { + SelectionChanged?.Invoke(this, new EventArgs()); + } + + private void TreeViewControlDataDoubleClick(object sender, EventArgs e) + { + viewCommands.OpenViewForSelection(); + } + + private void TreeViewControlDataDeleted(object sender, EventArgs e) + { + viewCommands.RemoveAllViewsForItem(e.Value); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.resx (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ProjectExplorer/ProjectExplorer.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Fill + + + + 0 + + + + 0, 0 + + + 0 + + + 375, 352 + + + 0 + + + treeViewControl + + + Core.Common.Controls.TreeView.TreeView, Core.Common.Controls.TreeView, Culture=neutral, PublicKeyToken=null + + + treeViewPanel + + + 0 + + + Fill + + + 0, 0 + + + 375, 352 + + + 5 + + + treeViewPanel + + + System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 6, 13 + + + 375, 352 + + + ProjectExplorer + + + System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/PropertyGridView/IPropertyResolver.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/PropertyGridView/IPropertyResolver.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/PropertyGridView/IPropertyResolver.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,37 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms.PropertyGridView +{ + /// + /// Interface for an object that is used to retrieve property objects corresponding to a data-object. + /// + public interface IPropertyResolver + { + /// + /// Returns object properties based on the provided . + /// + /// The source data to get the object properties for. + /// An object properties object, or null when no relevant properties object is found + /// or multiple matches are found. + object GetObjectProperties(object sourceData); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/PropertyGridView/PropertyGridView.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/PropertyGridView/PropertyGridView.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/PropertyGridView/PropertyGridView.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,300 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Linq; +using System.Reflection; +using System.Security.Permissions; +using System.Windows.Forms; +using Core.Common.Base; +using Core.Common.Controls.Views; +using Core.Gui.Properties; +using Core.Gui.PropertyBag; + +namespace Core.Gui.Forms.PropertyGridView +{ + /// + /// View for displaying the properties of an data object. + /// + public class PropertyGridView : PropertyGrid, IView, IObserver + { + private readonly IPropertyResolver propertyResolver; + + private object data; + private IObjectProperties objectProperties; + + /// + /// This delegate enabled asynchronous calls to methods without arguments. + /// + private delegate void ArgumentlessDelegate(); + + /// + /// Initializes a new instance of the class. + /// + /// The class responsible for finding the object properties + /// for a given data object. + /// Thrown when any input argument is null. + public PropertyGridView(IPropertyResolver propertyResolver) + { + if (propertyResolver == null) + { + throw new ArgumentNullException(nameof(propertyResolver)); + } + + HideTabsButton(); + DisableDescriptionAreaAutoSizing(); + TranslateToolTips(); + + PropertySort = PropertySort.Categorized; + + this.propertyResolver = propertyResolver; + Name = "PropertiesPanelGridView"; + } + + public void UpdateObserver() + { + RefreshPropertyGridView(); + } + + protected override void OnPropertySortChanged(EventArgs e) + { + // Needed for maintaining property order (no support for both categorized and alphabetical sorting) + if (PropertySort == PropertySort.CategorizedAlphabetical) + { + PropertySort = PropertySort.Categorized; + } + + base.OnPropertySortChanged(e); + } + + protected override void Dispose(bool disposing) + { + DisposeObjectProperties(); + + base.Dispose(disposing); + } + + private void RefreshPropertyGridView() + { + if (InvokeRequired) + { + ArgumentlessDelegate d = RefreshPropertyGridView; + Invoke(d, new object[0]); + } + else + { + Refresh(); + } + } + + #region IView Members + + public object Data + { + get + { + return data; + } + set + { + // Prevent redundant updates + if (data != null && data.Equals(value)) + { + return; + } + + DisposeObjectProperties(); + + data = value; + + SelectedObject = GetObjectProperties(data); + + var dynamicPropertyBag = SelectedObject as DynamicPropertyBag; + objectProperties = dynamicPropertyBag?.WrappedObject as IObjectProperties; + + if (objectProperties != null) + { + objectProperties.RefreshRequired += HandleRefreshRequired; + + var observableObjectProperties = objectProperties.Data as IObservable; + observableObjectProperties?.Attach(this); + } + } + } + + private void DisposeObjectProperties() + { + if (objectProperties != null) + { + objectProperties.RefreshRequired -= HandleRefreshRequired; + + var disposableObjectProperties = objectProperties as IDisposable; + disposableObjectProperties?.Dispose(); + + var observableObjectProperties = objectProperties.Data as IObservable; + observableObjectProperties?.Detach(this); + } + } + + private void HandleRefreshRequired(object sender, EventArgs e) + { + RefreshPropertyGridView(); + } + + private object GetObjectProperties(object sourceData) + { + return propertyResolver.GetObjectProperties(sourceData); + } + + #endregion + + #region Tab key navigation + + /// + /// Do special processing for Tab key. + /// http://www.codeproject.com/csharp/wdzPropertyGridUtils.asp + /// + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Tab || keyData == (Keys.Tab | Keys.Shift)) + { + GridItem selectedItem = SelectedGridItem; + GridItem root = selectedItem; + if (selectedItem == null) + { + return false; + } + + while (root.Parent != null) + { + root = root.Parent; + } + + // Find all expanded items and put them in a list. + var items = new List(); + AddExpandedItems(root, items); + + // Find selectedItem. + int foundIndex = items.IndexOf(selectedItem); + if ((keyData & Keys.Shift) == Keys.Shift) + { + foundIndex--; + if (foundIndex < 0) + { + foundIndex = items.Count - 1; + } + + SelectedGridItem = items[foundIndex]; + if (SelectedGridItem.GridItems.Count > 0) + { + SelectedGridItem.Expanded = false; + } + } + else + { + foundIndex++; + if (items.Count > 0) + { + if (foundIndex >= items.Count) + { + foundIndex = 0; + } + + SelectedGridItem = items[foundIndex]; + } + + if (SelectedGridItem.GridItems.Count > 0) + { + SelectedGridItem.Expanded = true; + } + } + + return true; + } + + return base.ProcessCmdKey(ref msg, keyData); + } + + private static void AddExpandedItems(GridItem parent, List items) + { + if (parent.PropertyDescriptor != null) + { + items.Add(parent); + } + + if (parent.Expanded) + { + foreach (GridItem child in parent.GridItems) + { + AddExpandedItems(child, items); + } + } + } + + #endregion + + #region Visualization tweaks + + /// + /// Removes the redundant "tabs" toolstrip button and its corresponding separator. + /// + private void HideTabsButton() + { + ToolStrip strip = Controls.OfType().First(); + strip.Items[3].Visible = false; + strip.Items[4].Visible = false; + } + + private void TranslateToolTips() + { + ToolStrip strip = Controls.OfType().First(); + strip.Items[0].ToolTipText = Resources.PropertyGridView_Order_Categorized; + strip.Items[1].ToolTipText = Resources.PropertyGridView_Order_Alphabetically; + } + + private void DisableDescriptionAreaAutoSizing() + { + foreach (object control in Controls) + { + Type type = control.GetType(); + + if (type.Name == "DocComment") + { + Type baseType = type.BaseType; + if (baseType != null) + { + FieldInfo field = baseType.GetField("userSized", BindingFlags.Instance | BindingFlags.NonPublic); + if (field != null) + { + field.SetValue(control, true); + } + } + + return; + } + } + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/PropertyGridView/PropertyResolver.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/PropertyGridView/PropertyResolver.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/PropertyGridView/PropertyResolver.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,134 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Linq; +using Core.Common.Util.Reflection; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using Core.Gui.PropertyBag; + +namespace Core.Gui.Forms.PropertyGridView +{ + /// + /// Class responsible for finding the that has been + /// registered for a given data-object. + /// + public class PropertyResolver : IPropertyResolver + { + private readonly IEnumerable propertyInfos; + + /// + /// Creates a new instance of with the given . + /// + /// The list of property information objects to obtain the object properties from. + /// Thrown when is null. + public PropertyResolver(IEnumerable propertyInfos) + { + if (propertyInfos == null) + { + throw new ArgumentNullException(nameof(propertyInfos), Resources.PropertyResolver_PropertyResolver_Cannot_create_PropertyResolver_without_list_of_PropertyInfo); + } + + this.propertyInfos = propertyInfos.ToArray(); + } + + public object GetObjectProperties(object sourceData) + { + if (sourceData == null) + { + return null; + } + + // 1. Match property information based on ObjectType and on AdditionalDataCheck: + PropertyInfo[] filteredPropertyInfos = propertyInfos.Where(pi => pi.DataType.IsInstanceOfType(sourceData)).ToArray(); + + // 2. Match property information based on object type inheritance, prioritizing most specialized object types: + filteredPropertyInfos = FilterPropertyInfoByTypeInheritance(filteredPropertyInfos, pi => pi.DataType); + + // 3. Match property information based on property type inheritance, prioritizing most specialized object property types: + filteredPropertyInfos = FilterPropertyInfoByTypeInheritance(filteredPropertyInfos, pi => pi.PropertyObjectType); + + if (filteredPropertyInfos.Length == 0) + { + // No object properties found: return 'null' so that no object properties are shown in the property grid + return null; + } + + if (filteredPropertyInfos.Length == 1) + { + return CreateObjectProperties(filteredPropertyInfos[0], sourceData); + } + + return null; + } + + private static PropertyInfo[] FilterPropertyInfoByTypeInheritance(PropertyInfo[] propertyInfo, Func getTypeAction) + { + int propertyInfoCount = propertyInfo.Length; + List propertyInfoWithUnInheritedType = propertyInfo.ToList(); + + for (var i = 0; i < propertyInfoCount; i++) + { + PropertyInfo propertyToBeConsidered = propertyInfo[i]; + Type firstType = getTypeAction(propertyToBeConsidered); + + for (var j = 0; j < propertyInfoCount; j++) + { + if (i == j) + { + continue; + } + + Type secondType = getTypeAction(propertyInfo[j]); + + if (firstType != secondType && secondType.Implements(firstType)) + { + propertyInfoWithUnInheritedType.Remove(propertyToBeConsidered); + + break; + } + } + } + + return propertyInfoWithUnInheritedType.Any() + ? propertyInfoWithUnInheritedType.ToArray() // One or more specific property information objects found: return the filtered list + : propertyInfo; // No specific property information found: return the original list + } + + private static object CreateObjectProperties(PropertyInfo propertyInfo, object sourceData) + { + try + { + // Try to create object properties for the source data + IObjectProperties objectProperties = propertyInfo.CreateInstance(sourceData); + + // Return a dynamic property bag containing the created object properties + return new DynamicPropertyBag(objectProperties); + } + catch (Exception) + { + return null; + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/RichTextFile.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/RichTextFile.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/RichTextFile.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,39 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms +{ + /// + /// Object that refers to an .rtf file. + /// + public class RichTextFile + { + /// + /// Gets or sets the title of the document (can be the file name). + /// + public string Name { get; set; } + + /// + /// Gets or sets the file path to use for loading the rich-text formatted file. + /// + public string FilePath { get; set; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/RichTextView.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/RichTextView.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/RichTextView.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,80 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms +{ + partial class RichTextView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 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(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + this.SuspendLayout(); + // + // richTextBox1 + // + this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.richTextBox1.Location = new System.Drawing.Point(0, 0); + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.ReadOnly = true; + this.richTextBox1.Size = new System.Drawing.Size(469, 340); + this.richTextBox1.TabIndex = 0; + this.richTextBox1.Text = ""; + // + // RichTextView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.richTextBox1); + this.Name = "RichTextView"; + this.Size = new System.Drawing.Size(469, 340); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.RichTextBox richTextBox1; + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/RichTextView.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/RichTextView.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/RichTextView.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,67 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.IO; +using System.Windows.Forms; +using Core.Common.Controls.Views; + +namespace Core.Gui.Forms +{ + /// + /// A view to display a instance. + /// + public partial class RichTextView : UserControl, IView + { + private RichTextFile richTextFile; + + /// + /// Initializes a new instance of the class. + /// + public RichTextView() + { + InitializeComponent(); + } + + #region IView Members + + public object Data + { + get + { + return richTextFile; + } + set + { + richTextFile = value as RichTextFile; + if (richTextFile != null && File.Exists(richTextFile.FilePath)) + { + richTextBox1.LoadFile(richTextFile.FilePath); + } + else + { + richTextBox1.Clear(); + } + } + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/RichTextView.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/RichTextView.resx (revision 0) +++ Core/Gui/src/Core.Gui/Forms/RichTextView.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/SelectItemDialog.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SelectItemDialog.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SelectItemDialog.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,117 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows.Forms; + +namespace Core.Gui.Forms +{ + partial class SelectItemDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 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(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SelectItemDialog)); + this.buttonOk = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.listViewItemTypes = new System.Windows.Forms.ListView(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.SuspendLayout(); + // + // buttonOk + // + resources.ApplyResources(this.buttonOk, "buttonOk"); + this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOk.Name = "buttonOk"; + this.buttonOk.UseVisualStyleBackColor = true; + this.buttonOk.Click += new System.EventHandler(this.ButtonOkClick); + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // listViewItemTypes + // + resources.ApplyResources(this.listViewItemTypes, "listViewItemTypes"); + this.listViewItemTypes.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.listViewItemTypes.HideSelection = false; + this.listViewItemTypes.LargeImageList = this.imageList; + this.listViewItemTypes.MultiSelect = false; + this.listViewItemTypes.Name = "listViewItemTypes"; + this.listViewItemTypes.SmallImageList = this.imageList; + this.listViewItemTypes.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listViewItemTypes.TileSize = new System.Drawing.Size(200, 30); + this.listViewItemTypes.UseCompatibleStateImageBehavior = false; + this.listViewItemTypes.View = System.Windows.Forms.View.Tile; + this.listViewItemTypes.DoubleClick += new System.EventHandler(this.ListViewItemTypesDoubleClick); + // + // imageList + // + this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; + resources.ApplyResources(this.imageList, "imageList"); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + // + // SelectItemDialog + // + this.AcceptButton = this.buttonOk; + resources.ApplyResources(this, "$this"); + this.Controls.Add(this.listViewItemTypes); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOk); + this.Name = "SelectItemDialog"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonOk; + private System.Windows.Forms.Button buttonCancel; + private ListView listViewItemTypes; + private System.Windows.Forms.ImageList imageList; + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/SelectItemDialog.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SelectItemDialog.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SelectItemDialog.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,146 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Controls.Dialogs; +using Core.Gui.Properties; + +namespace Core.Gui.Forms +{ + /// + /// Dialog that can be used to ask the user to select from a collection of options. + /// + public partial class SelectItemDialog : DialogBase + { + private readonly string text; + + /// + /// Initializes a new instance of the class. + /// + /// The dialog parent for which this dialog should be + /// shown on top. + /// The text to show in the dialog. + public SelectItemDialog(IWin32Window dialogParent, string text) : base(dialogParent, Resources.ExportIcon, 320, 220) + { + InitializeComponent(); + + this.text = text; + } + + /// + /// Gets the data object corresponding to the item selected by the user or null if + /// no selection was made. + /// + public object SelectedItemTag + { + get + { + return SelectedItem?.Tag; + } + } + + /// + /// Gets the name of the selected item or null if no selection was made. + /// + public string SelectedItemTypeName + { + get + { + return SelectedItem?.Name; + } + } + + /// + /// Adds an option element to the dialog. + /// + /// The name of the element. + /// The category of the element. + /// The image of the element. + /// The data corresponding to the element. + public void AddItemType(string name, string category, Image image, object tag) + { + if (!ContainsCategory(category)) + { + listViewItemTypes.Groups.Add(new ListViewGroup(category, category)); + } + + ListViewGroup group = listViewItemTypes.Groups[category]; + + imageList.Images.Add(category + "-" + name, image); + listViewItemTypes.Items.Add(name, name, imageList.Images.Count - 1); + listViewItemTypes.Items[listViewItemTypes.Items.Count - 1].Group = group; + listViewItemTypes.Items[listViewItemTypes.Items.Count - 1].Tag = tag; + } + + protected override Button GetCancelButton() + { + return buttonCancel; + } + + protected override void OnLoad(EventArgs e) + { + Text = text; + + base.OnLoad(e); + } + + private ListViewItem SelectedItem + { + get + { + if (listViewItemTypes.SelectedIndices.Count == 0) + { + return null; + } + + int selectedIndex = listViewItemTypes.SelectedIndices[0]; + return listViewItemTypes.Items[selectedIndex]; + } + } + + private bool ContainsCategory(string category) + { + return listViewItemTypes.Groups + .Cast() + .Any(listViewGroup => listViewGroup.Header == category); + } + + private void ButtonOkClick(object sender, EventArgs e) + { + if (SelectedItem == null) + { + MessageBox.Show(Resources.SelectItemDialog_buttonOk_Click_Please_select_an_item, + Resources.SelectItemDialog_buttonOk_Click_Error, + MessageBoxButtons.OK, + MessageBoxIcon.Error); + DialogResult = DialogResult.None; + } + } + + private void ListViewItemTypesDoubleClick(object sender, EventArgs e) + { + buttonOk.PerformClick(); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/SelectItemDialog.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SelectItemDialog.resx (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SelectItemDialog.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Bottom, Right + + + + 300, 151 + + + 75, 23 + + + + 1 + + + OK + + + buttonOk + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + 382, 151 + + + 75, 23 + + + 2 + + + Annuleren + + + buttonCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Bottom, Left, Right + + + 17, 17 + + + 16, 16 + + + 12, 12 + + + 445, 129 + + + 0 + + + listViewItemTypes + + + System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 54 + + + 469, 184 + + + CenterParent + + + imageList + + + System.Windows.Forms.ImageList, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + SelectItemDialog + + + Core.Common.Controls.Dialogs.DialogBase, Core.Common.Controls, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/SelectViewDialog.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SelectViewDialog.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SelectViewDialog.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,120 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms +{ + partial class SelectViewDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 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(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SelectViewDialog)); + this.buttonOk = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.listBox = new System.Windows.Forms.ListBox(); + this.label1 = new System.Windows.Forms.Label(); + this.checkBoxDefault = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // buttonOk + // + resources.ApplyResources(this.buttonOk, "buttonOk"); + this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOk.Name = "buttonOk"; + this.buttonOk.UseVisualStyleBackColor = true; + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // listBox + // + resources.ApplyResources(this.listBox, "listBox"); + this.listBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; + this.listBox.FormattingEnabled = true; + this.listBox.Name = "listBox"; + this.listBox.Sorted = true; + this.listBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ListBoxDrawItem); + this.listBox.SelectedIndexChanged += new System.EventHandler(this.ListBoxSelectedIndexChanged); + this.listBox.DoubleClick += new System.EventHandler(this.ListBoxDoubleClick); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // checkBoxDefault + // + resources.ApplyResources(this.checkBoxDefault, "checkBoxDefault"); + this.checkBoxDefault.Name = "checkBoxDefault"; + this.checkBoxDefault.UseVisualStyleBackColor = true; + this.checkBoxDefault.CheckedChanged += new System.EventHandler(this.CheckBoxDefaultCheckedChanged); + // + // SelectViewDialog + // + this.AcceptButton = this.buttonOk; + resources.ApplyResources(this, "$this"); + this.Controls.Add(this.checkBoxDefault); + this.Controls.Add(this.label1); + this.Controls.Add(this.listBox); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOk); + this.Name = "SelectViewDialog"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonOk; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.ListBox listBox; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckBox checkBoxDefault; + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/SelectViewDialog.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SelectViewDialog.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SelectViewDialog.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,160 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Drawing; +using System.Windows.Forms; +using Core.Common.Controls.Dialogs; +using Core.Gui.Properties; + +namespace Core.Gui.Forms +{ + /// + /// Dialog for selecting a view for a given piece of data. + /// + public partial class SelectViewDialog : DialogBase + { + private List items; + + /// + /// Initializes a new instance of the class. + /// + /// The dialog parent for which this dialog should be + /// shown on top. + public SelectViewDialog(IWin32Window dialogParent) : base(dialogParent, Resources.arrow_000_medium_question_mark, 350, 200) + { + InitializeComponent(); + + Font lbFont = listBox.Font; + Graphics g = listBox.CreateGraphics(); + + using (var defaultItemFont = new Font(lbFont.FontFamily, lbFont.Size, FontStyle.Bold)) + { + SizeF itemSize = g.MeasureString("TEST", defaultItemFont); + listBox.ItemHeight = (int) itemSize.Height; + } + } + + /// + /// Gets or sets the items to select from. + /// + public List Items + { + get + { + return items; + } + set + { + items = value; + listBox.DataSource = items; + listBox.SelectedIndex = 0; + } + } + + /// + /// Gets the selected item. + /// + public string SelectedItem + { + get + { + return (string) listBox.SelectedItem; + } + } + + /// + /// Gets or sets the name of the default view for the data. + /// + public string DefaultViewName { get; set; } + + protected override Button GetCancelButton() + { + return buttonCancel; + } + + private void ListBoxDoubleClick(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + + private void ListBoxDrawItem(object sender, DrawItemEventArgs e) + { + string itemAsString = listBox.Items[e.Index].ToString(); + Font lbFont = listBox.Font; + + bool selected = (e.State & DrawItemState.Selected) == DrawItemState.Selected; + e.DrawBackground(); + + if (itemAsString == DefaultViewName) + { + string defaultIndicatorText = Resources.SelectViewDialog_listBox_DrawItem_Default; + var defaultItemFont = new Font(lbFont.FontFamily, lbFont.Size, FontStyle.Bold); + + SizeF itemSize = e.Graphics.MeasureString(itemAsString, defaultItemFont); + SizeF indicatorSize = e.Graphics.MeasureString(defaultIndicatorText, defaultItemFont); + + var boundsIndicator = new RectangleF(e.Bounds.Left + itemSize.Width, + e.Bounds.Top, indicatorSize.Width, e.Bounds.Height); + + e.Graphics.DrawString(itemAsString, defaultItemFont, selected ? new SolidBrush(SystemColors.HighlightText) : Brushes.Black, e.Bounds); + e.Graphics.DrawString(defaultIndicatorText, defaultItemFont, Brushes.LightGray, boundsIndicator); + } + else + { + e.Graphics.DrawString(itemAsString, lbFont, selected ? new SolidBrush(SystemColors.HighlightText) : Brushes.Black, e.Bounds); + } + + e.DrawFocusRectangle(); + } + + private void ListBoxSelectedIndexChanged(object sender, EventArgs e) + { + checkBoxDefault.Checked = listBox.SelectedItem != null + && listBox.SelectedItem.ToString() == DefaultViewName; + } + + private void CheckBoxDefaultCheckedChanged(object sender, EventArgs e) + { + string previousName = DefaultViewName; + if (listBox.SelectedItem.ToString() == DefaultViewName) + { + DefaultViewName = checkBoxDefault.Checked + ? listBox.SelectedItem.ToString() + : null; + } + else + { + if (checkBoxDefault.Checked) + { + DefaultViewName = listBox.SelectedItem.ToString(); + } + } + + if (previousName != DefaultViewName) + { + listBox.Refresh(); + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/SelectViewDialog.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SelectViewDialog.resx (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SelectViewDialog.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Bottom, Right + + + + 235, 300 + + + 75, 23 + + + + 1 + + + OK + + + buttonOk + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Bottom, Right + + + 316, 300 + + + 75, 23 + + + 2 + + + Annuleren + + + buttonCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Top, Bottom, Left, Right + + + 12, 26 + + + 379, 264 + + + 0 + + + listBox + + + System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + 12, 9 + + + 126, 13 + + + 4 + + + Selecteer een weergave: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Bottom, Left + + + True + + + 12, 303 + + + 141, 17 + + + 5 + + + Gebruiken als standaard + + + checkBoxDefault + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 403, 334 + + + NoControl + + + CenterParent + + + Openen met... + + + SelectViewDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/SplashScreen/SplashScreen.xaml =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SplashScreen/SplashScreen.xaml (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SplashScreen/SplashScreen.xaml (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: Core/Gui/src/Core.Gui/Forms/SplashScreen/SplashScreen.xaml.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/SplashScreen/SplashScreen.xaml.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/SplashScreen/SplashScreen.xaml.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,141 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Windows; +using System.Windows.Media; + +namespace Core.Gui.Forms.SplashScreen +{ + /// + /// Interaction logic for SplashScreen.xaml + /// + public partial class SplashScreen + { + private string versionText; + private string supportPhoneNumber; + private string supportEmailAddress; + + /// + /// Initializes a new instance of the class. + /// + public SplashScreen() + { + InitializeComponent(); + + VersionText = ""; + } + + /// + /// Gets or sets the version to be shown. + /// + public string VersionText + { + private get + { + return versionText; + } + set + { + versionText = value; + InvalidateVisual(); + } + } + + /// + /// Gets or sets the support e-mail. + /// + public string SupportEmail + { + private get + { + return supportEmailAddress; + } + set + { + supportEmailAddress = value; + InvalidateVisual(); + } + } + + /// + /// Gets or sets the support phone number. + /// + public string SupportPhoneNumber + { + private get + { + return supportPhoneNumber; + } + set + { + supportPhoneNumber = value; + InvalidateVisual(); + } + } + + /// + /// Shuts this instance down. + /// + public void Shutdown() + { + Focusable = false; + Close(); + } + + protected override void OnRender(DrawingContext drawingContext) + { + base.OnRender(drawingContext); + + if (LabelVersion.Content.ToString() != VersionText) + { + LabelVersion.Content = VersionText; + } + + SetSupportValues(); + } + + private void SetSupportValues() + { + Visibility supportVisibility = string.IsNullOrWhiteSpace(SupportPhoneNumber) || string.IsNullOrWhiteSpace(SupportEmail) ? Visibility.Collapsed : Visibility.Visible; + + LabelSupportTitle.Visibility = supportVisibility; + LabelSupportPhoneNumberTitle.Visibility = supportVisibility; + LabelSupportPhoneNumber.Visibility = supportVisibility; + LabelSupportEmailAddressTitle.Visibility = supportVisibility; + LabelSupportEmailAddress.Visibility = supportVisibility; + + if (supportVisibility != Visibility.Visible) + { + return; + } + + if (LabelSupportPhoneNumber.Content.ToString() != SupportPhoneNumber) + { + LabelSupportPhoneNumber.Content = SupportPhoneNumber; + } + + if (LabelSupportEmailAddress.Content.ToString() != SupportEmail) + { + LabelSupportEmailAddress.Content = SupportEmail; + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ViewHost/AvalonDockViewHost.xaml =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ViewHost/AvalonDockViewHost.xaml (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ViewHost/AvalonDockViewHost.xaml (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: Core/Gui/src/Core.Gui/Forms/ViewHost/AvalonDockViewHost.xaml.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ViewHost/AvalonDockViewHost.xaml.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ViewHost/AvalonDockViewHost.xaml.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,489 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Drawing; +using System.Linq; +using System.Windows.Forms; +using System.Windows.Forms.Integration; +using Core.Common.Controls.Views; +using Core.Common.Util.Drawing; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Core.Gui.Forms.ViewHost +{ + /// + /// Implementation of a view host based on AvalonDock. + /// + public partial class AvalonDockViewHost : IViewHost + { + private readonly List toolViews; + private readonly List documentViews; + private readonly List hostControls; + + private IView activeView; + private IView activeDocumentView; + + public event EventHandler ActiveDocumentViewChanging; + public event EventHandler ActiveDocumentViewChanged; + public event EventHandler ActiveViewChanged; + public event EventHandler ViewOpened; + public event EventHandler ViewBroughtToFront; + public event EventHandler ViewClosed; + + /// + /// Creates a new instance of the class. + /// + public AvalonDockViewHost() + { + InitializeComponent(); + DummyPanelA.Hide(); + DummyPanelB.Hide(); + + toolViews = new List(); + documentViews = new List(); + hostControls = new List(); + + DockingManager.ActiveContentChanged += OnActiveContentChanged; + } + + public IEnumerable DocumentViews + { + get + { + return documentViews; + } + } + + public IEnumerable ToolViews + { + get + { + return toolViews; + } + } + + public IView ActiveDocumentView + { + get + { + return activeDocumentView; + } + private set + { + if (activeDocumentView == value) + { + return; + } + + OnActiveDocumentViewChanging(); + + activeDocumentView = value; + + OnActiveDocumentViewChanged(); + } + } + + public void AddDocumentView(IView view) + { + var control = view as Control; + if (control == null) + { + return; + } + + // If the view was already added, just bring it to front + if (documentViews.Contains(view) || toolViews.Contains(view)) + { + BringToFront(view); + return; + } + + var hostControl = new WindowsFormsHost + { + Child = control + }; + var layoutDocument = new LayoutDocument + { + Title = view.Text, + Content = hostControl + }; + + PerformWithoutChangingActiveContent(() => AddLayoutDocument(layoutDocument)); + + BringToFront(layoutDocument); + + documentViews.Add(view); + hostControls.Add(hostControl); + + layoutDocument.Closed += OnLayoutDocumentClosed; + + OnViewOpened(view); + } + + public void AddToolView(IView view, ToolViewLocation toolViewLocation) + { + var control = view as Control; + if (control == null) + { + return; + } + + // If the view was already added, just bring it to front + if (documentViews.Contains(view) || toolViews.Contains(view)) + { + BringToFront(view); + return; + } + + var hostControl = new WindowsFormsHost + { + Child = control + }; + var layoutAnchorable = new LayoutAnchorable + { + Content = hostControl, + Title = view.Text + }; + + PerformWithoutChangingActiveContent(() => AddLayoutAnchorable(layoutAnchorable, toolViewLocation)); + + BringToFront(layoutAnchorable); + + toolViews.Add(view); + hostControls.Add(hostControl); + + layoutAnchorable.Hiding += OnLayoutAnchorableHiding; + layoutAnchorable.Closing += OnLayoutAnchorableClosing; + + OnViewOpened(view); + } + + public void Remove(IView view) + { + if (documentViews.Contains(view)) + { + var layoutDocument = GetLayoutContent(view); + + PerformWithoutChangingActiveContent(() => + { + layoutDocument.Close(); + UpdateDockingManager(); + }); + + if (ReferenceEquals(ActiveDocumentView, view)) + { + ActiveDocumentView = null; + } + } + else if (toolViews.Contains(view)) + { + var layoutAnchorable = GetLayoutContent(view); + + PerformWithoutChangingActiveContent(() => + { + layoutAnchorable.Hide(); + UpdateDockingManager(); + }); + } + } + + public void BringToFront(IView view) + { + LayoutContent layoutContent; + + if (documentViews.Contains(view)) + { + layoutContent = GetLayoutContent(view); + } + else + { + layoutContent = toolViews.Contains(view) + ? GetLayoutContent(view) + : null; + } + + BringToFront(layoutContent); + + OnViewBroughtToFront(view); + } + + public void SetImage(IView view, Image image) + { + var layoutContent = GetLayoutContent(view); + if (layoutContent != null) + { + layoutContent.IconSource = image.AsBitmapImage(); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + foreach (IView view in documentViews.Concat(toolViews).ToArray()) + { + Remove(view); + } + + DockingManager.ActiveContent = null; + } + + private void BringToFront(LayoutContent layoutContent) + { + PerformWithoutChangingActiveContent(() => + { + if (layoutContent != null && !layoutContent.IsActive) + { + layoutContent.IsActive = true; + + UpdateDockingManager(); + } + }); + } + + private void OnActiveDocumentViewChanging() + { + ActiveDocumentViewChanging?.Invoke(this, new EventArgs()); + } + + private void OnActiveDocumentViewChanged() + { + ActiveDocumentViewChanged?.Invoke(this, new EventArgs()); + } + + private void OnActiveViewChanged() + { + ActiveViewChanged?.Invoke(this, new ViewChangeEventArgs(GetView(DockingManager.ActiveContent))); + } + + private void OnViewOpened(IView view) + { + ViewOpened?.Invoke(this, new ViewChangeEventArgs(view)); + } + + private void OnViewBroughtToFront(IView view) + { + ViewBroughtToFront?.Invoke(this, new ViewChangeEventArgs(view)); + } + + private void OnViewClosed(IView view) + { + ViewClosed?.Invoke(this, new ViewChangeEventArgs(view)); + } + + private void OnActiveContentChanged(object sender, EventArgs eventArgs) + { + UnfocusActiveView(); + + activeView = GetView(DockingManager.ActiveContent); + + if (documentViews.Contains(activeView)) + { + ActiveDocumentView = activeView; + } + else if (DockingManager.ActiveContent == null) + { + ActiveDocumentView = null; + } + + OnActiveViewChanged(); + } + + /// + /// Performs unfocus action for the current active view. + /// + /// + /// Raising unfocus events manually is necessary when changing focus from one WindowsFormsHost to another (also see + /// https://msdn.microsoft.com/en-us/library/ms751797(v=vs.100).aspx#Windows_Presentation_Foundation_Application_Hosting). + /// + private void UnfocusActiveView() + { + var containerControl = activeView as IContainerControl; + if (containerControl == null) + { + return; + } + + while (containerControl.ActiveControl is IContainerControl) + { + containerControl = (IContainerControl) containerControl.ActiveControl; + } + + PerformWithoutChangingActiveContent(() => containerControl.ActiveControl = null); + } + + private void OnLayoutDocumentClosed(object sender, EventArgs e) + { + var layoutDocument = (LayoutDocument) sender; + + layoutDocument.Closed -= OnLayoutDocumentClosed; + + CloseView(GetView(layoutDocument.Content)); + } + + private static void OnLayoutAnchorableClosing(object sender, CancelEventArgs eventArgs) + { + var layoutAnchorable = (LayoutAnchorable) sender; + + layoutAnchorable.Hide(); + + eventArgs.Cancel = true; + } + + private void OnLayoutAnchorableHiding(object sender, EventArgs e) + { + var layoutAnchorable = (LayoutAnchorable) sender; + + layoutAnchorable.Hiding -= OnLayoutAnchorableHiding; + layoutAnchorable.Closing -= OnLayoutAnchorableClosing; + + CloseView(GetView(layoutAnchorable.Content)); + } + + private void CloseView(IView view) + { + if (documentViews.Contains(view)) + { + documentViews.Remove(view); + } + else + { + toolViews.Remove(view); + } + + CleanupHostControl(view); + + view.Data = null; + view.Dispose(); + + OnViewClosed(view); + } + + private void PerformWithoutChangingActiveContent(Action actionToPerform) + { + DockingManager.ActiveContentChanged -= OnActiveContentChanged; + object currentActiveContent = DockingManager.ActiveContent; + + actionToPerform(); + + DockingManager.ActiveContent = currentActiveContent; + DockingManager.ActiveContentChanged += OnActiveContentChanged; + } + + /// + /// This method can be called in order to get rid of problems caused by AvalonDock's latency. + /// + private void UpdateDockingManager() + { + DockingManager.UpdateLayout(); + } + + private void CleanupHostControl(IView view) + { + WindowsFormsHost hostControl = hostControls.First(hc => hc.Child == view); + + hostControl.Child = null; // Prevent views from getting disposed here by clearing the child + hostControl.Dispose(); + + hostControls.Remove(hostControl); + } + + private T GetLayoutContent(IView view) where T : LayoutContent + { + return DockingManager.Layout.Descendents() + .OfType() + .FirstOrDefault(d => GetView(d.Content) == view); + } + + private void AddLayoutDocument(LayoutDocument layoutDocument) + { + LayoutDocumentPaneGroup.Descendents() + .OfType() + .First() + .Children.Add(layoutDocument); + } + + private void AddLayoutAnchorable(LayoutAnchorable layoutAnchorable, ToolViewLocation toolViewLocation) + { + LayoutAnchorablePaneGroup layoutAnchorablePaneGroup; + if (!Enum.IsDefined(typeof(ToolViewLocation), toolViewLocation)) + { + throw new InvalidEnumArgumentException(nameof(toolViewLocation), (int) toolViewLocation, typeof(ToolViewLocation)); + } + + switch (toolViewLocation) + { + case ToolViewLocation.Left: + if (LeftLayoutAnchorablePaneGroup.Parent == null) + { + LeftLayoutAnchorablePaneGroup.Children.Add(new LayoutAnchorablePane()); + LeftRightLayoutTarget.Children.Insert(0, LeftLayoutAnchorablePaneGroup); + } + + layoutAnchorablePaneGroup = LeftLayoutAnchorablePaneGroup; + break; + case ToolViewLocation.Bottom: + if (BottomLayoutAnchorablePaneGroup.Parent == null) + { + BottomLayoutAnchorablePaneGroup.Children.Add(new LayoutAnchorablePane()); + BottomLayoutTarget.Children.Add(BottomLayoutAnchorablePaneGroup); + } + + layoutAnchorablePaneGroup = BottomLayoutAnchorablePaneGroup; + break; + case ToolViewLocation.Right: + if (RightLayoutAnchorablePaneGroup.Parent == null) + { + RightLayoutAnchorablePaneGroup.Children.Add(new LayoutAnchorablePane()); + LeftRightLayoutTarget.Children.Add(RightLayoutAnchorablePaneGroup); + } + + layoutAnchorablePaneGroup = RightLayoutAnchorablePaneGroup; + break; + default: + throw new NotSupportedException(); + } + + layoutAnchorablePaneGroup.Descendents() + .OfType() + .First() + .Children.Add(layoutAnchorable); + } + + private static IView GetView(object content) + { + var windowsFormsHost = content as WindowsFormsHost; + return windowsFormsHost?.Child as IView; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ViewHost/DocumentViewController.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ViewHost/DocumentViewController.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ViewHost/DocumentViewController.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,280 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Linq; +using System.Windows.Forms; +using Core.Common.Controls.Views; +using Core.Common.Util.Reflection; +using Core.Gui.Plugin; + +namespace Core.Gui.Forms.ViewHost +{ + /// + /// Class responsible for finding a view given some data object. + /// + public class DocumentViewController : IDocumentViewController + { + private readonly IViewHost viewHost; + private readonly ViewInfo[] viewInfos; + private readonly IWin32Window dialogParent; + + private readonly IDictionary> openedViewLookup = new Dictionary>(); + + /// + /// Initializes a new instance of the class. + /// + /// The view host. + /// The sequence of available view info objects. + /// The parent object for which dialogs should be shown on top. + public DocumentViewController(IViewHost viewHost, IEnumerable viewInfos, IWin32Window dialogParent) + { + this.viewHost = viewHost; + this.viewInfos = viewInfos.ToArray(); + this.dialogParent = dialogParent; + + DefaultViewTypes = new Dictionary(); + + viewHost.ViewClosed += ViewHostOnViewClosed; + } + + /// + /// Gets the default view types registered for data object types, that can be used to + /// automatically resolve a particular view when multiple candidates are available. + /// + /// The keys in this dictionary are the object types and the values the + /// corresponding view types. + public IDictionary DefaultViewTypes { get; } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public bool OpenViewForData(object data, bool alwaysShowDialog = false) + { + if (data == null) + { + return false; + } + + ViewInfo[] viewInfoList = FilterOnInheritance(GetViewInfosFor(data)).ToArray(); + if (viewInfoList.Length == 0) + { + return false; + } + + if (!alwaysShowDialog) + { + if (viewInfoList.Length == 1) + { + CreateViewFromViewInfo(data, viewInfoList[0]); + return true; + } + + // Create default view + Type defaultType = GetDefaultViewType(data); + ViewInfo defaultViewInfo = viewInfoList.FirstOrDefault(vi => vi.ViewType == defaultType); + + if (defaultViewInfo != null) + { + CreateViewFromViewInfo(data, defaultViewInfo); + return true; + } + } + + // Create chosen view + ViewInfo chosenViewInfo = GetViewInfoUsingDialog(data, viewInfoList); + if (chosenViewInfo == null) + { + return false; + } + + CreateViewFromViewInfo(data, chosenViewInfo); + + return true; + } + + public void CloseAllViewsFor(object data) + { + if (data == null) + { + return; + } + + foreach (IView view in viewHost.DocumentViews.Where(view => ShouldRemoveViewForData(view, data)).ToArray()) + { + viewHost.Remove(view); + } + } + + public IEnumerable GetViewInfosFor(object data) + { + return viewInfos.Where(vi => data.GetType().Implements(vi.DataType) && vi.AdditionalDataCheck(data)); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + viewHost.ViewClosed -= ViewHostOnViewClosed; + } + } + + private static IEnumerable FilterOnInheritance(IEnumerable compatibleStandaloneViewInfos) + { + ViewInfo[] viewInfosArray = compatibleStandaloneViewInfos.ToArray(); + + // filter on inheritance + IEnumerable dataTypes = viewInfosArray.Select(i => i.DataType); + return viewInfosArray.Where(i => !dataTypes.Any(t => t != i.DataType && t.Implements(i.DataType))); + } + + private void CreateViewFromViewInfo(object data, ViewInfo viewInfo) + { + Tuple view; + openedViewLookup.TryGetValue(data, out view); + + if (view != null) + { + viewHost.BringToFront(view.Item1); + return; + } + + view = new Tuple(CreateViewForData(data, viewInfo), viewInfo); + + openedViewLookup.Add(data, view); + + viewHost.AddDocumentView(view.Item1); + viewHost.SetImage(view.Item1, viewInfo.Image); + } + + private static IView CreateViewForData(object data, ViewInfo viewInfo) + { + IView view = viewInfo.CreateInstance(data); + + view.Data = viewInfo.GetViewData(data); + + viewInfo.AfterCreate(view, data); + + view.Text = viewInfo.GetViewName(view, data); + + return view; + } + + private bool ShouldRemoveViewForData(IView view, object data) + { + ViewInfo viewInfo = openedViewLookup.Single(openedView => ReferenceEquals(view, openedView.Value.Item1)).Value.Item2; + + if (viewInfo == null) + { + return false; + } + + bool isViewData = data.GetType().Implements(viewInfo.DataType) + && Equals(viewInfo.GetViewData(data), view.Data); + + return isViewData || viewInfo.CloseForData(view, data); + } + + private void ViewHostOnViewClosed(object sender, ViewChangeEventArgs viewChangeEventArgs) + { + object data = openedViewLookup.Where(kv => ReferenceEquals(kv.Value.Item1, viewChangeEventArgs.View)) + .Select(kv => kv.Key) + .FirstOrDefault(); + + if (data != null) + { + openedViewLookup.Remove(data); + } + } + + private Type GetDefaultViewType(object dataObject) + { + Type selectionType = dataObject.GetType(); + + return DefaultViewTypes.ContainsKey(selectionType) + ? DefaultViewTypes[selectionType] + : null; + } + + private void ClearDefaultView(object data) + { + Type selectedItemType = data.GetType(); + + if (DefaultViewTypes.ContainsKey(selectedItemType)) + { + DefaultViewTypes.Remove(selectedItemType); + } + } + + private void SetDefaultView(Type selectedViewType, object data) + { + Type selectedItemType = data.GetType(); + + if (DefaultViewTypes.ContainsKey(selectedItemType)) + { + DefaultViewTypes[selectedItemType] = selectedViewType; + } + else + { + DefaultViewTypes.Add(selectedItemType, selectedViewType); + } + } + + private ViewInfo GetViewInfoUsingDialog(object data, IEnumerable viewInfoList) + { + Type defaultViewTypeForData = GetDefaultViewType(data); + string defaultViewName = defaultViewTypeForData != null + ? viewInfoList.First(vi => vi.ViewType == defaultViewTypeForData).Description + : null; + + Dictionary viewTypeDictionary = viewInfoList.ToDictionary(vi => vi.Description ?? vi.ViewType.Name); + using (var viewSelector = new SelectViewDialog(dialogParent) + { + DefaultViewName = defaultViewName, + Items = viewTypeDictionary.Keys.ToList() + }) + { + if (viewSelector.ShowDialog() != DialogResult.OK) + { + return null; + } + + ViewInfo selectedViewInfo = viewTypeDictionary[viewSelector.SelectedItem]; + + if (viewSelector.DefaultViewName == null) + { + ClearDefaultView(data); + } + else + { + ViewInfo defaultViewInfo = viewTypeDictionary[viewSelector.DefaultViewName]; + SetDefaultView(defaultViewInfo.ViewType, data); + } + + return selectedViewInfo; + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ViewHost/IDocumentViewController.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ViewHost/IDocumentViewController.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ViewHost/IDocumentViewController.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,65 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Gui.Plugin; + +namespace Core.Gui.Forms.ViewHost +{ + /// + /// Interface for an object capable of: + /// + /// + /// adding document views to a ; + /// + /// + /// finding document views in a ; + /// + /// + /// removing document views from a . + /// + /// + /// + public interface IDocumentViewController : IDisposable + { + /// + /// Opens a view for . + /// + /// The data to open a view for. + /// Always present the user with a dialog to choose + /// the view that has to be opened. + bool OpenViewForData(object data, bool alwaysShowDialog = false); + + /// + /// Closes all views for . + /// + /// The data object to close all views for. + void CloseAllViewsFor(object data); + + /// + /// Gets the view info objects for . + /// + /// The data to obtain the view info objects for. + /// The matching view info objects. + IEnumerable GetViewInfosFor(object data); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ViewHost/IViewHost.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ViewHost/IViewHost.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ViewHost/IViewHost.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,112 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Drawing; +using Core.Common.Controls.Views; + +namespace Core.Gui.Forms.ViewHost +{ + /// + /// Interface for an object capable of hosting document views and tool views. + /// + public interface IViewHost : IDisposable + { + /// + /// Fired before has changed. + /// + event EventHandler ActiveDocumentViewChanging; + + /// + /// Fired after has changed. + /// + event EventHandler ActiveDocumentViewChanged; + + /// + /// Fired after the active document or tool view has changed. + /// + event EventHandler ActiveViewChanged; + + /// + /// Fired when a document view or a tool view has been opened. + /// + event EventHandler ViewOpened; + + /// + /// Fired when an already opened document view or tool view is brought to front. + /// + event EventHandler ViewBroughtToFront; + + /// + /// Fired when a document view or a tool view has been closed. + /// + event EventHandler ViewClosed; + + /// + /// Gets the added document views. + /// + IEnumerable DocumentViews { get; } + + /// + /// Gets the added tool views. + /// + IEnumerable ToolViews { get; } + + /// + /// Gets the active document view. + /// + IView ActiveDocumentView { get; } + + /// + /// Adds a document view and makes it active. + /// + /// The document view to add. + /// + void AddDocumentView(IView view); + + /// + /// Adds a tool view. + /// + /// The tool view add. + /// The location where the tool view should be added. + void AddToolView(IView view, ToolViewLocation toolViewLocation); + + /// + /// Removes a document view or tool view. + /// + /// The view to remove. + void Remove(IView view); + + /// + /// Brings a document view or tool view to the front. + /// + /// The view to bring to front. + void BringToFront(IView view); + + /// + /// Sets the image for a document view or tool view. + /// + /// The view to set the image for. + /// The image. + void SetImage(IView view, Image image); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ViewHost/ToolViewLocation.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ViewHost/ToolViewLocation.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ViewHost/ToolViewLocation.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,44 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Forms.ViewHost +{ + /// + /// Enumeration that defines tool view locations. + /// + public enum ToolViewLocation + { + /// + /// Left of the location reserved for document views. + /// + Left, + + /// + /// Right of the location reserved for document views. + /// + Right, + + /// + /// Below the location reserved for document views. + /// + Bottom + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Forms/ViewHost/ViewChangeEventArgs.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Forms/ViewHost/ViewChangeEventArgs.cs (revision 0) +++ Core/Gui/src/Core.Gui/Forms/ViewHost/ViewChangeEventArgs.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Controls.Views; + +namespace Core.Gui.Forms.ViewHost +{ + /// + /// Event arguments for when there has been a view change. + /// + public class ViewChangeEventArgs : EventArgs + { + /// + /// Creates a new instance of . + /// + /// The view for which there has been a change. + public ViewChangeEventArgs(IView view) + { + View = view; + } + + /// + /// Gets the view for which there was a change. + /// + public IView View { get; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/GuiCore.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/GuiCore.cs (revision 0) +++ Core/Gui/src/Core.Gui/GuiCore.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,780 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Windows; +using Core.Common.Base; +using Core.Common.Base.Data; +using Core.Common.Base.Storage; +using Core.Common.Controls.TreeView; +using Core.Common.Controls.Views; +using Core.Common.Util.Extensions; +using Core.Common.Util.Settings; +using Core.Gui.Commands; +using Core.Gui.ContextMenu; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Forms.MessageWindow; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.Forms.ViewHost; +using Core.Gui.Helpers; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using Core.Gui.Settings; +using log4net; +using log4net.Appender; +using log4net.Repository.Hierarchy; +using SplashScreen = Core.Gui.Forms.SplashScreen.SplashScreen; +using WindowsApplication = System.Windows.Forms.Application; + +namespace Core.Gui +{ + /// + /// Gui class provides graphical user functionality for the application. + /// + public class GuiCore : IGui + { + private static readonly ILog log = LogManager.GetLogger(typeof(GuiCore)); + + private static bool isAlreadyRunningInstanceOfIGui; + private static string instanceCreationStackTrace; + + private readonly Observer projectObserver; + private ISelectionProvider currentSelectionProvider; + + private bool isExiting; + private bool runFinished; + private SplashScreen splashScreen; + + /// + /// Initializes a new instance of the class. + /// + /// The main window. + /// The project store. + /// The project migrator. + /// The project factory. + /// The fixed settings. + /// Thrown when another + /// instance is running. + /// Thrown when any parameter is null. + public GuiCore(IMainWindow mainWindow, IStoreProject projectStore, IMigrateProject projectMigrator, IProjectFactory projectFactory, GuiCoreSettings fixedSettings) + { + // error detection code, make sure we use only a single instance of GuiCore at a time + if (isAlreadyRunningInstanceOfIGui) + { + isAlreadyRunningInstanceOfIGui = false; // reset to that the consecutive creations won't fail. + throw new InvalidOperationException( + string.Format(CultureInfo.CurrentCulture, + Resources.GuiCore_Only_a_single_instance_of_Riskeer_is_allowed_at_the_same_time_per_process_Make_sure_that_the_previous_instance_was_disposed_correctly_stack_trace_0, + instanceCreationStackTrace)); + } + + if (mainWindow == null) + { + throw new ArgumentNullException(nameof(mainWindow)); + } + + if (projectStore == null) + { + throw new ArgumentNullException(nameof(projectStore)); + } + + if (projectMigrator == null) + { + throw new ArgumentNullException(nameof(projectMigrator)); + } + + if (projectFactory == null) + { + throw new ArgumentNullException(nameof(projectFactory)); + } + + if (fixedSettings == null) + { + throw new ArgumentNullException(nameof(fixedSettings)); + } + + MainWindow = mainWindow; + ProjectStore = projectStore; + FixedSettings = fixedSettings; + + isAlreadyRunningInstanceOfIGui = true; + instanceCreationStackTrace = new StackTrace().ToString(); + + Plugins = new List(); + + viewCommandHandler = new ViewCommandHandler(this, this, this); + + StorageCommands = new StorageCommandHandler(projectStore, projectMigrator, projectFactory, + this, dialogBasedInquiryHelper, MainWindow); + + importCommandHandler = new GuiImportHandler(MainWindow, Plugins.SelectMany(p => p.GetImportInfos()), dialogBasedInquiryHelper); + exportCommandHandler = new GuiExportHandler(MainWindow, Plugins.SelectMany(p => p.GetExportInfos())); + updateCommandHandler = new GuiUpdateHandler(MainWindow, Plugins.SelectMany(p => p.GetUpdateInfos()), dialogBasedInquiryHelper); + + WindowsApplication.EnableVisualStyles(); + ViewPropertyEditor.ViewCommands = ViewCommands; + + ProjectOpened += ApplicationProjectOpened; + BeforeProjectOpened += ApplicationBeforeProjectOpened; + projectObserver = new Observer(UpdateTitle); + + Project = projectFactory.CreateNewProject(); + } + + public IPropertyResolver PropertyResolver { get; private set; } + + public IStoreProject ProjectStore { get; } + + #region Implementation: ISettingsOwner + + public GuiCoreSettings FixedSettings { get; } + + #endregion + + /// + /// Runs the user interface, causing all user interface components to initialize, + /// loading plugins, opening a saved project and displaying the main window. + /// + /// Path to the project to be opened. (optional) + public void Run(string projectPath = null) + { + DateTime startTime = DateTime.Now; + + ConfigureLogging(); + + ShowSplashScreen(); + + InitializeProjectFromPath(projectPath); + + Initialize(); + + log.InfoFormat(Resources.GuiCore_Run_Started_in_0_f2_sec, (DateTime.Now - startTime).TotalSeconds); + + runFinished = true; + + HideSplashScreen(); + + MessageWindowLogAppender.Instance.Enabled = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void ExitApplication() + { + if (isExiting) + { + return; //already got here before + } + + // Store project? + if (!StorageCommands.HandleUnsavedChanges()) + { + // User pressed cancel + return; + } + + isExiting = true; + + if (Application.Current != null) + { + Application.Current.Shutdown(); + } + } + + #region Implementation: IContextMenuBuilderProvider + + public IContextMenuBuilder Get(object value, TreeViewControl treeViewControl) + { + if (applicationFeatureCommands == null) + { + throw new InvalidOperationException("Call IGui.Run in order to initialize dependencies before getting the ContextMenuBuilder."); + } + + return new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + ViewCommands, + value, + treeViewControl); + } + + #endregion + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + projectObserver.Dispose(); + + if (Plugins != null) + { + foreach (PluginBase plugin in Plugins.ToArray()) + { + DeactivatePlugin(plugin); + } + } + + isExiting = true; + + mainWindow?.UnsubscribeFromGui(); + + Selection = null; + + if (ViewHost != null) + { + ViewHost.Dispose(); + ViewHost.ViewClosed -= OnViewClosed; + ViewHost.ViewClosed -= OnActiveDocumentViewChanged; + ViewHost.ActiveDocumentViewChanged -= OnActiveDocumentViewChanged; + ViewHost.ActiveViewChanged -= OnActiveViewChanged; + } + + if (currentSelectionProvider != null) + { + currentSelectionProvider.SelectionChanged -= OnSelectionChanged; + } + + if (mainWindow != null && !mainWindow.IsWindowDisposed) + { + mainWindow.Dispose(); + mainWindow = null; + } + + if (DocumentViewController != null) + { + DocumentViewController.Dispose(); + DocumentViewController = null; + } + + splashScreen = null; + + MessageWindowLogAppender.Instance.MessageWindow = null; + + RemoveLogging(); + Plugins = null; + } + + #region Prevent nasty Windows.Forms memory leak (keeps references to databinding objects / controls + + Assembly systemAssembly = typeof(Component).Assembly; + Type reflectTypeDescriptionProviderType = + systemAssembly.GetType("System.ComponentModel.ReflectTypeDescriptionProvider"); + FieldInfo propertyCacheInfo = reflectTypeDescriptionProviderType.GetField("_propertyCache", + BindingFlags.Static | + BindingFlags.NonPublic); + var propertyCache = (Hashtable) propertyCacheInfo?.GetValue(null); + propertyCache?.Clear(); + + FieldInfo extendedPropertyCacheInfo = reflectTypeDescriptionProviderType.GetField( + "_extendedPropertyCache", BindingFlags.Static | BindingFlags.NonPublic); + var extendedPropertyCache = extendedPropertyCacheInfo?.GetValue(null) as Hashtable; + extendedPropertyCache?.Clear(); + + FieldInfo eventCacheInfo = reflectTypeDescriptionProviderType.GetField("_eventCache", + BindingFlags.Static | + BindingFlags.NonPublic); + var eventCache = eventCacheInfo?.GetValue(null) as Hashtable; + eventCache?.Clear(); + + FieldInfo attributeCacheInfo = reflectTypeDescriptionProviderType.GetField("_attributeCache", + BindingFlags.Static | + BindingFlags.NonPublic); + var attributeCache = attributeCacheInfo?.GetValue(null) as Hashtable; + attributeCache?.Clear(); + + Type typeDescriptorType = systemAssembly.GetType("System.ComponentModel.TypeDescriptor"); + FieldInfo providerTableInfo = typeDescriptorType.GetField("_providerTable", + BindingFlags.Static | BindingFlags.NonPublic); + var providerTable = providerTableInfo?.GetValue(null) as Hashtable; + providerTable?.Clear(); + + FieldInfo providerTypeTableInfo = typeDescriptorType.GetField("_providerTypeTable", + BindingFlags.Static | BindingFlags.NonPublic); + var providerTypeTable = providerTypeTableInfo?.GetValue(null) as Hashtable; + providerTypeTable?.Clear(); + + FieldInfo defaultProvidersInfo = typeDescriptorType.GetField("_defaultProviders", + BindingFlags.Static | BindingFlags.NonPublic); + var defaultProviders = defaultProvidersInfo?.GetValue(null) as Hashtable; + defaultProviders?.Clear(); + + #endregion + + GC.Collect(); + + instanceCreationStackTrace = ""; + isAlreadyRunningInstanceOfIGui = false; + } + + private void InitializeProjectFromPath(string projectPath) + { + bool isPathGiven = !string.IsNullOrWhiteSpace(projectPath); + if (isPathGiven) + { + StorageCommands.OpenExistingProject(projectPath); + } + } + + private void DeactivatePlugin(PluginBase plugin) + { + try + { + plugin.Deactivate(); + } + catch (Exception exception) + { + log.Error(Resources.GuiCore_ActivatePlugins_Exception_during_plugin_gui_deactivation, exception); + } + + plugin.Dispose(); + + Plugins.Remove(plugin); + } + + private void ApplicationProjectOpened(IProject newProject) + { + mainWindow?.ValidateItems(); + + projectObserver.Observable = newProject; + UpdateTitle(); + mainWindow?.UpdateProjectExplorer(); + } + + private void ApplicationBeforeProjectOpened(IProject oldProject) + { + ViewCommands.RemoveAllViewsForItem(project); + } + + private static void ConfigureLogging() + { + // configure logging + Logger rootLogger = ((Hierarchy) LogManager.GetRepository()).Root; + + if (!rootLogger.Appenders.Cast().Any(a => a is MessageWindowLogAppender)) + { + rootLogger.AddAppender(new MessageWindowLogAppender()); + rootLogger.Repository.Configured = true; + } + } + + private static void RemoveLogging() + { + Logger rootLogger = ((Hierarchy) LogManager.GetRepository()).Root; + MessageWindowLogAppender messageWindowLogAppender = rootLogger.Appenders.Cast().OfType().FirstOrDefault(); + if (messageWindowLogAppender != null) + { + rootLogger.RemoveAppender(messageWindowLogAppender); + } + } + + private void Initialize() + { + InitializeWindows(); + + InitializePlugins(); + } + + private void ShowSplashScreen() + { + splashScreen = new SplashScreen + { + VersionText = SettingsHelper.Instance.ApplicationVersion + }; + + splashScreen.IsVisibleChanged += delegate + { + if (splashScreen.IsVisible) + { + return; + } + + if (!runFinished) // splash screen was closed before gui started. + { + log.Info(Resources.GuiCore_ShowSplashScreen_User_has_canceled_start_Exiting); + Environment.Exit(1); + } + }; + + splashScreen.Show(); + } + + private void HideSplashScreen() + { + splashScreen.Shutdown(); + } + + private void InitializeMainWindow() + { + mainWindow.Loaded += delegate + { + if (ViewHost.ToolViews.Contains(mainWindow.PropertyGrid)) + { + ViewHost.BringToFront(mainWindow.PropertyGrid); + } + + if (ViewHost.ToolViews.Contains(mainWindow.MessageWindow)) + { + ViewHost.BringToFront(mainWindow.MessageWindow); + } + + if (ViewHost.ToolViews.Contains(mainWindow.ProjectExplorer)) + { + ViewHost.BringToFront(mainWindow.ProjectExplorer); + } + + mainWindow.ValidateItems(); + }; + + mainWindow.Closing += delegate(object sender, CancelEventArgs e) + { + if (isExiting) + { + return; + } + + e.Cancel = true; //cancel closing: let Exit handle it + ExitApplication(); + }; + } + + private void InitializeWindows() + { + InitializeMainWindow(); + + ViewHost = mainWindow.ViewHost; + ViewHost.ViewClosed += OnViewClosed; + ViewHost.ViewClosed += OnActiveDocumentViewChanged; + ViewHost.ActiveDocumentViewChanged += OnActiveDocumentViewChanged; + ViewHost.ActiveViewChanged += OnActiveViewChanged; + + DocumentViewController = new DocumentViewController(ViewHost, Plugins.SelectMany(p => p.GetViewInfos()), mainWindow); + + PropertyResolver = new PropertyResolver(Plugins.SelectMany(p => p.GetPropertyInfos())); + applicationFeatureCommands = new ApplicationFeatureCommandHandler(PropertyResolver, mainWindow); + + mainWindow.InitializeToolWindows(); + + mainWindow.SubscribeToGui(); + + UpdateTitle(); + } + + private void OnViewClosed(object sender, ViewChangeEventArgs e) + { + if (ReferenceEquals(currentSelectionProvider, e.View)) + { + currentSelectionProvider.SelectionChanged -= OnSelectionChanged; + currentSelectionProvider = null; + + Selection = null; + } + } + + private void OnActiveDocumentViewChanged(object sender, EventArgs e) + { + if (mainWindow != null && !mainWindow.IsWindowDisposed) + { + mainWindow.ValidateItems(); + } + } + + private void OnActiveViewChanged(object sender, ViewChangeEventArgs e) + { + if (HandleActivatingCurrentSelectionProvidingDocumentView(e.View)) + { + return; + } + + var selectionProvider = e.View as ISelectionProvider; + if (selectionProvider == null) + { + HandleDeactivatingCurrentSelectionProvidingDocumentView(); + + return; + } + + if (currentSelectionProvider != null) + { + currentSelectionProvider.SelectionChanged -= OnSelectionChanged; + } + + currentSelectionProvider = selectionProvider; + currentSelectionProvider.SelectionChanged += OnSelectionChanged; + + Selection = currentSelectionProvider.Selection; + } + + private bool HandleActivatingCurrentSelectionProvidingDocumentView(IView activeView) + { + var handled = false; + + if (ReferenceEquals(currentSelectionProvider, activeView) && ViewHost.DocumentViews.Contains(activeView)) + { + currentSelectionProvider.SelectionChanged += OnSelectionChanged; + + handled = true; + } + + return handled; + } + + private void HandleDeactivatingCurrentSelectionProvidingDocumentView() + { + if (currentSelectionProvider != null && ViewHost.DocumentViews.Contains((IView) currentSelectionProvider)) + { + currentSelectionProvider.SelectionChanged -= OnSelectionChanged; + } + } + + private void OnSelectionChanged(object sender, EventArgs eventArgs) + { + Selection = currentSelectionProvider.Selection; + } + + private void InitializePlugins() + { + Plugins.ForEachElementDo(p => p.Gui = this); + + var problematicPlugins = new List(); + + // Try to activate all plugins + foreach (PluginBase plugin in Plugins) + { + try + { + plugin.Activate(); + } + catch + { + problematicPlugins.Add(plugin); + } + } + + // Deactivate and remove all problematic plugins + foreach (PluginBase problematicPlugin in problematicPlugins) + { + DeactivatePlugin(problematicPlugin); + } + } + + ~GuiCore() + { + Dispose(false); + } + + #region Implementation: IProjectOwner + + private IProject project; + public event Action BeforeProjectOpened; + public event Action ProjectOpened; + + public string ProjectFilePath { get; private set; } + + public IProject Project + { + get + { + return project; + } + private set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value), @"There should always be a project."); + } + + if (!ReferenceEquals(project, value)) + { + OnBeforeProjectOpened(); + project = value; + OnProjectOpened(); + } + } + } + + private void OnBeforeProjectOpened() + { + BeforeProjectOpened?.Invoke(project); + } + + private void OnProjectOpened() + { + ProjectOpened?.Invoke(project); + } + + public void SetProject(IProject newProject, string projectPath) + { + Project = newProject; + ProjectFilePath = projectPath; + } + + #endregion + + #region Implementation: IApplicationSelection + + private object selection; + + public object Selection + { + get + { + return selection; + } + set + { + if (selection == value) + { + return; + } + + selection = value; + + if (mainWindow == null) + { + return; + } + + if (mainWindow.PropertyGrid != null) + { + mainWindow.PropertyGrid.Data = selection; + } + + if (!isExiting && !mainWindow.IsWindowDisposed) + { + mainWindow.ValidateItems(); + } + } + } + + #endregion + + #region Implementation: ICommandsOwner + + private ApplicationFeatureCommandHandler applicationFeatureCommands; + private readonly ViewCommandHandler viewCommandHandler; + private readonly GuiImportHandler importCommandHandler; + private readonly GuiExportHandler exportCommandHandler; + private readonly GuiUpdateHandler updateCommandHandler; + + public IApplicationFeatureCommands ApplicationCommands + { + get + { + return applicationFeatureCommands; + } + } + + public IStorageCommands StorageCommands { get; } + + public IViewCommands ViewCommands + { + get + { + return viewCommandHandler; + } + } + + #endregion + + #region Implementation: IViewController + + public IViewHost ViewHost { get; private set; } + + public IDocumentViewController DocumentViewController { get; private set; } + + #endregion + + #region Implementation: IPluginHost + + public List Plugins { get; private set; } + + public IEnumerable GetTreeNodeInfos() + { + return Plugins.SelectMany(pluginGui => pluginGui.GetTreeNodeInfos()); + } + + public IEnumerable GetAllDataWithViewDefinitionsRecursively(object rootValue) + { + var resultSet = new HashSet(); + foreach (object childDataInstance in Plugins.SelectMany(p => p.GetChildDataWithViewDefinitions(rootValue)).Distinct()) + { + resultSet.Add(childDataInstance); + + if (!ReferenceEquals(rootValue, childDataInstance)) + { + foreach (object dataWithViewDefined in GetAllDataWithViewDefinitionsRecursively(childDataInstance)) + { + resultSet.Add(dataWithViewDefined); + } + } + } + + return resultSet; + } + + #endregion + + #region Implementation: IMainWindowController + + private MainWindow mainWindow; + private DialogBasedInquiryHelper dialogBasedInquiryHelper; + + public IMainWindow MainWindow + { + get + { + return mainWindow; + } + private set + { + mainWindow = (MainWindow) value; + mainWindow.SetGui(this); + dialogBasedInquiryHelper = new DialogBasedInquiryHelper(MainWindow); + } + } + + private void UpdateTitle() + { + if (mainWindow != null) + { + mainWindow.Title = string.Format(CultureInfo.CurrentCulture, + "{0} - {1} {2}", + Project.Name, + FixedSettings.MainWindowTitle, + SettingsHelper.Instance.ApplicationVersion); + } + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Helpers/DialogBasedInquiryHelper.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Helpers/DialogBasedInquiryHelper.cs (revision 0) +++ Core/Gui/src/Core.Gui/Helpers/DialogBasedInquiryHelper.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,150 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Windows.Forms; +using Core.Gui.Properties; +using CoreCommonBaseResources = Core.Common.Base.Properties.Resources; + +namespace Core.Gui.Helpers +{ + /// + /// Class which inquires the user for application inputs based on dialogs. + /// + public class DialogBasedInquiryHelper : IInquiryHelper + { + private readonly IWin32Window dialogParent; + + /// + /// Creates a new instance of . + /// + /// The parent window to provide to the created + /// dialogs. + /// Thrown when + /// is null. + public DialogBasedInquiryHelper(IWin32Window dialogParent) + { + if (dialogParent == null) + { + throw new ArgumentNullException(nameof(dialogParent)); + } + + this.dialogParent = dialogParent; + } + + public string GetSourceFileLocation(string fileFilter) + { + string filePath = null; + using (var dialog = new OpenFileDialog + { + Multiselect = false, + Title = Resources.OpenFileDialog_Title, + Filter = fileFilter + }) + { + DialogResult result = dialog.ShowDialog(dialogParent); + if (result == DialogResult.OK) + { + filePath = dialog.FileName; + } + } + + return filePath; + } + + public string GetTargetFileLocation(string fileFilter, string suggestedFileName) + { + string filePath = null; + using (var dialog = new SaveFileDialog + { + Title = Resources.SaveFileDialog_Title, + Filter = fileFilter, + FileName = suggestedFileName + }) + { + DialogResult result = dialog.ShowDialog(dialogParent); + if (result == DialogResult.OK) + { + filePath = dialog.FileName; + } + } + + return filePath; + } + + public string GetTargetFolderLocation() + { + string folderPath = null; + using (var dialog = new FolderBrowserDialog + { + ShowNewFolderButton = true, + Description = Resources.SaveFileDialog_Title + }) + { + DialogResult result = dialog.ShowDialog(dialogParent); + if (result == DialogResult.OK) + { + folderPath = dialog.SelectedPath; + } + } + + return folderPath; + } + + public bool InquireContinuation(string query) + { + DialogResult dialog = MessageBox.Show( + dialogParent, + query, + CoreCommonBaseResources.Confirm, + MessageBoxButtons.OKCancel); + return dialog == DialogResult.OK; + } + + public OptionalStepResult InquirePerformOptionalStep(string workflowDescription, string query) + { + DialogResult confirmation = MessageBox.Show(dialogParent, + query, + workflowDescription, + MessageBoxButtons.YesNoCancel); + + if (!Enum.IsDefined(typeof(DialogResult), confirmation)) + { + throw new InvalidEnumArgumentException(nameof(confirmation), + (int) confirmation, + typeof(DialogResult)); + } + + switch (confirmation) + { + case DialogResult.Cancel: + return OptionalStepResult.Cancel; + case DialogResult.Yes: + return OptionalStepResult.PerformOptionalStep; + case DialogResult.No: + return OptionalStepResult.SkipOptionalStep; + default: + throw new NotSupportedException("Dialogbox should only return the above values."); + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Helpers/ExportHelper.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Helpers/ExportHelper.cs (revision 0) +++ Core/Gui/src/Core.Gui/Helpers/ExportHelper.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,72 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Util; + +namespace Core.Gui.Helpers +{ + /// + /// Class with helper methods that can be used during export. + /// + public static class ExportHelper + { + /// + /// Gets the file path to export to. + /// + /// Helper responsible for performing information inquiries. + /// The file filter generator to use. + /// A path to a file, which may or may not exist yet, or null if no location + /// was chosen. + /// Thrown when any parameter is null. + public static string GetFilePath(IInquiryHelper inquiryHelper, FileFilterGenerator fileFilterGenerator) + { + if (inquiryHelper == null) + { + throw new ArgumentNullException(nameof(inquiryHelper)); + } + + if (fileFilterGenerator == null) + { + throw new ArgumentNullException(nameof(fileFilterGenerator)); + } + + return inquiryHelper.GetTargetFileLocation(fileFilterGenerator.Filter, null); + } + + /// + /// Gets the folder path to export to. + /// + /// Helper responsible for performing information inquiries. + /// A path to a folder, or null if no location was chosen. + /// Thrown when + /// is null. + public static string GetFolderPath(IInquiryHelper inquiryHelper) + { + if (inquiryHelper == null) + { + throw new ArgumentNullException(nameof(inquiryHelper)); + } + + return inquiryHelper.GetTargetFolderLocation(); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Helpers/IInquiryHelper.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Helpers/IInquiryHelper.cs (revision 0) +++ Core/Gui/src/Core.Gui/Helpers/IInquiryHelper.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,70 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Helpers +{ + /// + /// Specifies the interface for classes that can be used to inquire information from + /// the user. + /// + public interface IInquiryHelper + { + /// + /// Returns the path of an existing file that the user has chosen. + /// + /// A filter to which the path returned complies. + /// A file location, or null if no location was chosen. + string GetSourceFileLocation(string fileFilter); + + /// + /// Returns the path to a file, which may or may not exist yet, that the user has chosen. + /// + /// A filter to which the path returned complies. + /// The initial file name the user can choose. + /// A path to a file, which may or may not exist yet, or null if no location + /// was chosen. + string GetTargetFileLocation(string fileFilter, string suggestedFileName); + + /// + /// Returns the path to a folder that the user has chosen. + /// + /// A path to a file, which may or may not exist yet, or null if no location + /// was chosen. + string GetTargetFolderLocation(); + + /// + /// Gets the confirmation of a user. + /// + /// The query to which the user needs to answer. + /// true if the user confirmed, false otherwise. + bool InquireContinuation(string query); + + /// + /// Checks with the user if a certain optional step in some workflow should be + /// performed or not. + /// + /// The short descriptive text on the workflow + /// currently being performed. + /// The query to which the user needs to answer. + /// How the workflow should continue. + OptionalStepResult InquirePerformOptionalStep(string workflowDescription, string query); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/IGui.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/IGui.cs (revision 0) +++ Core/Gui/src/Core.Gui/IGui.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,56 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Base.Storage; +using Core.Gui.Commands; +using Core.Gui.ContextMenu; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.PropertyBag; +using Core.Gui.Selection; +using Core.Gui.Settings; + +namespace Core.Gui +{ + /// + /// Provides graphical user interface logic required to work with an application. + /// + public interface IGui : ICommandsOwner, ISettingsOwner, IProjectOwner, + IApplicationSelection, IViewController, IContextMenuBuilderProvider, + IMainWindowController, IPluginsHost, IDisposable + { + /// + /// Gets the object responsible for retrieving the + /// instance for a given data object for the application to use. + /// + IPropertyResolver PropertyResolver { get; } + + /// + /// Gets the object responsible for perform storage actions. + /// + IStoreProject ProjectStore { get; } + + /// + /// Terminates the application. + /// + void ExitApplication(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/IMainWindowController.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/IMainWindowController.cs (revision 0) +++ Core/Gui/src/Core.Gui/IMainWindowController.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,37 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Gui.Forms.MainWindow; + +namespace Core.Gui +{ + /// + /// Interface that declares members that allow for controlling the main window of + /// the application. + /// + public interface IMainWindowController + { + /// + /// Gets main window of the graphical user interface. + /// + IMainWindow MainWindow { get; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/IPluginsHost.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/IPluginsHost.cs (revision 0) +++ Core/Gui/src/Core.Gui/IPluginsHost.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,53 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Collections; +using System.Collections.Generic; +using Core.Common.Controls.TreeView; +using Core.Gui.Plugin; + +namespace Core.Gui +{ + /// + /// Interface describing the object that hosts all the loaded graphical user interface + /// plugins of the application. + /// + public interface IPluginsHost + { + /// + /// Gets the list of plugins. + /// + List Plugins { get; } + + /// + /// Queries the plugins to get all data with view definitions recursively, given a + /// piece of hierarchical data. + /// + /// The root data object. + /// An enumeration of all (child)data that have view definitions declared. + IEnumerable GetAllDataWithViewDefinitionsRecursively(object rootValue); + + /// + /// Retrieves all the defined on the configured plugins. + /// + IEnumerable GetTreeNodeInfos(); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/IProjectOwner.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/IProjectOwner.cs (revision 0) +++ Core/Gui/src/Core.Gui/IProjectOwner.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,61 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Base.Data; + +namespace Core.Gui +{ + /// + /// Interface declaring members related to owning a . + /// + public interface IProjectOwner + { + /// + /// Occurs just before a new instance is available at . + /// + event Action BeforeProjectOpened; + + /// + /// Occurs when a new instance is available at . + /// + event Action ProjectOpened; + + /// + /// Gets the project of the application. + /// + IProject Project { get; } + + /// + /// Gets the project path of the application. + /// + string ProjectFilePath { get; } + + /// + /// Sets the project and the path of the project that was used for obtaining it. + /// + /// The project that is used in the application. + /// The file location where the was + /// loaded from, or null if it was not loaded from a file source. + /// Thrown when is null. + void SetProject(IProject newProject, string projectPath); + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/IViewController.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/IViewController.cs (revision 0) +++ Core/Gui/src/Core.Gui/IViewController.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,41 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Gui.Forms.ViewHost; + +namespace Core.Gui +{ + /// + /// Interface for controller that controls views in the application. + /// + public interface IViewController + { + /// + /// Gets the view host. + /// + IViewHost ViewHost { get; } + + /// + /// Gets the document view controller. + /// + IDocumentViewController DocumentViewController { get; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/OpenProjectActivity.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/OpenProjectActivity.cs (revision 0) +++ Core/Gui/src/Core.Gui/OpenProjectActivity.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,331 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.IO; +using Core.Common.Base.Data; +using Core.Common.Base.Service; +using Core.Common.Base.Storage; +using Core.Gui.Properties; +using log4net; +using CoreCommonBaseResources = Core.Common.Base.Properties.Resources; + +namespace Core.Gui +{ + /// + /// Activity that handles opening an . + /// + public class OpenProjectActivity : Activity + { + private readonly string filePath; + private readonly IProjectOwner projectOwner; + private readonly IProjectFactory projectFactory; + private readonly IStoreProject storage; + private readonly ILog log = LogManager.GetLogger(typeof(OpenProjectActivity)); + private readonly string migratedProjectFilePath; + private readonly IMigrateProject migrator; + private readonly int totalNumberOfSteps = 2; + private IProject openedProject; + private bool cancel; + + /// + /// Creates a new instance of . + /// + /// All mandatory properties for being + /// able to open a project. + /// Optional: Properties for migrating + /// the project to the current version. + /// Thrown when + /// is null. + /// Thrown when any input argument has invalid values. + public OpenProjectActivity(OpenProjectConstructionProperties requiredOpenProjectProperties, + ProjectMigrationConstructionProperties optionalProjectMigrationProperties = null) + { + if (requiredOpenProjectProperties == null) + { + throw new ArgumentNullException(nameof(requiredOpenProjectProperties)); + } + + ValidateOpenProjectProperties(requiredOpenProjectProperties); + if (optionalProjectMigrationProperties != null) + { + ValidateProjectMigrationProperties(optionalProjectMigrationProperties); + + migratedProjectFilePath = optionalProjectMigrationProperties.MigrationFilePath; + migrator = optionalProjectMigrationProperties.Migrator; + totalNumberOfSteps = 3; + } + + filePath = requiredOpenProjectProperties.FilePath; + projectOwner = requiredOpenProjectProperties.ProjectOwner; + projectFactory = requiredOpenProjectProperties.ProjectFactory; + storage = requiredOpenProjectProperties.ProjectStorage; + + Description = Resources.OpenProjectActivity_Open_project; + } + + protected override void OnRun() + { + cancel = false; + var currentStepNumber = 1; + ClearOpenedProject(); + + if (migrator != null && !MigrateProject(currentStepNumber++)) + { + return; + } + + LoadProject(currentStepNumber); + } + + protected override void OnCancel() + { + cancel = true; + } + + protected override void OnFinish() + { + switch (State) + { + case ActivityState.Executed: + InitializeSuccssfulOpenedProject(); + break; + case ActivityState.Failed: + InitializeEmptyProject(); + break; + case ActivityState.Canceled: + ClearOpenedProject(); + break; + } + } + + private string FilePathTakingMigrationIntoAccount + { + get + { + return migratedProjectFilePath ?? filePath; + } + } + + /// + /// Migrates the project. + /// + /// The current step number. + /// true if migration was successful, false otherwise. + private bool MigrateProject(int currentStepNumber) + { + UpdateProgressText(Resources.OpenProjectActivity_ProgressTextStepName_MigrateProject, + currentStepNumber, + totalNumberOfSteps); + + try + { + bool migrationSuccessful = migrator.Migrate(filePath, migratedProjectFilePath); + + if (cancel) + { + return false; + } + + if (!migrationSuccessful) + { + State = ActivityState.Failed; + return false; + } + } + catch (ArgumentException e) + { + if (cancel) + { + return false; + } + + log.Error(e.Message, e); + State = ActivityState.Failed; + return false; + } + + return true; + } + + private void LoadProject(int currentStepNumber) + { + UpdateProgressText(Resources.OpenProjectActivity_ProgressTextStepName_ReadProject, + currentStepNumber, + totalNumberOfSteps); + try + { + openedProject = storage.LoadProject(FilePathTakingMigrationIntoAccount); + } + catch (StorageException e) + { + if (cancel) + { + return; + } + + log.Error(e.Message, e.InnerException); + } + + if (cancel) + { + return; + } + + if (openedProject == null) + { + State = ActivityState.Failed; + } + } + + private void ClearOpenedProject() + { + openedProject = null; + } + + private void InitializeEmptyProject() + { + UpdateProgressText(Resources.OpenProjectActivity_ProgressTextStepName_InitializeEmptyProject, + totalNumberOfSteps, + totalNumberOfSteps); + + projectOwner.SetProject(projectFactory.CreateNewProject(), null); + } + + private void InitializeSuccssfulOpenedProject() + { + UpdateProgressText(Resources.OpenProjectActivity_ProgressTextStepName_InitializeProject, + totalNumberOfSteps, + totalNumberOfSteps); + + projectOwner.SetProject(openedProject, FilePathTakingMigrationIntoAccount); + openedProject.Name = Path.GetFileNameWithoutExtension(FilePathTakingMigrationIntoAccount); + openedProject.NotifyObservers(); + } + + /// + /// Updates the progress text. + /// + /// A short description of the current step. + /// The number of the current step. + /// The total numbers of steps. + private void UpdateProgressText(string currentStepName, int currentStep, int totalSteps) + { + ProgressText = string.Format(CultureInfo.CurrentCulture, + CoreCommonBaseResources.Activity_UpdateProgressText_CurrentStepNumber_0_of_TotalStepsNumber_1_StepDescription_2_, + currentStep, totalSteps, currentStepName); + } + + /// + /// Validates the construction arguments required for opening a project file. + /// + /// The construction arguments to be validated. + /// Thrown when any construction property of + /// is invalid. + private static void ValidateOpenProjectProperties(OpenProjectConstructionProperties requiredOpenProjectProperties) + { + if (requiredOpenProjectProperties.FilePath == null) + { + throw new ArgumentException(@"Filepath should be set.", nameof(requiredOpenProjectProperties)); + } + + if (requiredOpenProjectProperties.ProjectOwner == null) + { + throw new ArgumentException(@"Project owner should be set.", nameof(requiredOpenProjectProperties)); + } + + if (requiredOpenProjectProperties.ProjectFactory == null) + { + throw new ArgumentException(@"Project factory should be set.", nameof(requiredOpenProjectProperties)); + } + + if (requiredOpenProjectProperties.ProjectStorage == null) + { + throw new ArgumentException(@"Project storage should be set.", nameof(requiredOpenProjectProperties)); + } + } + + /// + /// Validates the construction arguments required for migrating a project file. + /// + /// The construction arguments to be validated. + /// Thrown when any construction property of + /// is invalid. + private static void ValidateProjectMigrationProperties(ProjectMigrationConstructionProperties optionalProjectMigrationProperties) + { + if (optionalProjectMigrationProperties.Migrator == null) + { + throw new ArgumentException(@"Project migrator should be set.", nameof(optionalProjectMigrationProperties)); + } + + if (optionalProjectMigrationProperties.MigrationFilePath == null) + { + throw new ArgumentException(@"Migration target file path should be set.", nameof(optionalProjectMigrationProperties)); + } + } + + /// + /// All construction properties related to opening a project file. + /// + public class OpenProjectConstructionProperties + { + /// + /// Filepath to the project file that should be opened. + /// + public string FilePath { get; set; } + + /// + /// The to be updated with the newly opened project. + /// + public IProjectOwner ProjectOwner { get; set; } + + /// + /// The to create a default project in case of + /// an error scenario. + /// + public IProjectFactory ProjectFactory { get; set; } + + /// + /// The object used to open the file at . + /// + public IStoreProject ProjectStorage { get; set; } + } + + /// + /// All construction properties related to migrating a project file. + /// + public class ProjectMigrationConstructionProperties + { + /// + /// The responsible for performing the migration. + /// + public IMigrateProject Migrator { get; set; } + + /// + /// The file path to where the migrate project should be written to. This path + /// will override with + /// regards of opening the project. + /// + public string MigrationFilePath { get; set; } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/OptionalStepResult.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/OptionalStepResult.cs (revision 0) +++ Core/Gui/src/Core.Gui/OptionalStepResult.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,44 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui +{ + /// + /// Indicates how an optional step in some workflow should be handled. + /// + public enum OptionalStepResult + { + /// + /// The optional step should be executed. + /// + PerformOptionalStep, + + /// + /// The optional step should be skipped. + /// + SkipOptionalStep, + + /// + /// Cancel the whole workflow. + /// + Cancel + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Plugin/ExportInfo.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Plugin/ExportInfo.cs (revision 0) +++ Core/Gui/src/Core.Gui/Plugin/ExportInfo.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,169 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Base.IO; +using Core.Gui.Properties; + +namespace Core.Gui.Plugin +{ + /// + /// Information for creating an exporter for a particular data object. + /// + public class ExportInfo + { + /// + /// Gets or sets the data type associated with this export info. + /// + public Type DataType { get; set; } + + /// + /// Gets or sets the method used to create a . Function arguments: + /// + /// The data to export. + /// The output file path. + /// out - The created exporter. + /// + /// + public Func CreateFileExporter { get; set; } + + /// + /// Gets or sets the method used to determine whether or not the export routine should be enabled. Function arguments: + /// + /// The data to export. + /// out - true if the export should be enabled, false otherwise. + /// + /// + public Func IsEnabled { get; set; } + + /// + /// Gets or sets the name of the export information. + /// + public string Name { get; set; } + + /// + /// Gets or sets the file extension of the export information. + /// + public string Extension { get; set; } + + /// + /// Gets or sets the category of the export information. + /// + /// Should never return null. + public string Category { get; set; } = Resources.ExportInfo_Default_category; + + /// + /// Gets or sets the image of the export information. + /// + /// Should never return null. + public Image Image { get; set; } = Resources.ExportIcon; + + /// + /// Gets or sets the method used to get the path where the export should save the data. Function arguments: + /// + /// out - the path to export to. + /// + /// + public Func GetExportPath { get; set; } + } + + /// + /// Information for creating an exporter for a particular data object. + /// + /// The data type associated with this export info. + public class ExportInfo + { + /// + /// Gets the data type associated with this export info. + /// + public Type DataType => typeof(TData); + + /// + /// Gets or sets the method used to create a . Function arguments: + /// + /// The data to export. + /// The output file path. + /// out - The created exporter. + /// + /// + public Func CreateFileExporter { get; set; } + + /// + /// Gets or sets the method used to determine whether or not the export routine should be enabled. Function arguments: + /// + /// The data to export. + /// out - true if the export should be enabled, false otherwise. + /// + /// + public Func IsEnabled { get; set; } + + /// + /// Gets or sets the name of the export information. + /// + public string Name { get; set; } + + /// + /// Gets or sets the file extension of the export information. + /// + public string Extension { get; set; } + + /// + /// Gets or sets the category of the export information. + /// + /// Should never return null. + public string Category { get; set; } = Resources.ExportInfo_Default_category; + + /// + /// Gets or sets the image of the export information. + /// + /// Should never return null. + public Image Image { get; set; } = Resources.ExportIcon; + + /// + /// Gets or sets the method used to get the path where the export should save the data. Function arguments: + /// + /// out - the path to export to. + /// + /// + public Func GetExportPath { get; set; } + + /// + /// Performs an implicit conversion from to . + /// + /// The export information to convert. + /// The result of the conversion. + public static implicit operator ExportInfo(ExportInfo exportInfo) + { + return new ExportInfo + { + DataType = exportInfo.DataType, + CreateFileExporter = (data, filePath) => exportInfo.CreateFileExporter?.Invoke((TData) data, filePath), + IsEnabled = data => exportInfo.IsEnabled == null || exportInfo.IsEnabled((TData) data), + Name = exportInfo.Name, + Category = exportInfo.Category, + Image = exportInfo.Image, + Extension = exportInfo.Extension, + GetExportPath = () => exportInfo.GetExportPath?.Invoke() + }; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Plugin/ImportInfo.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Plugin/ImportInfo.cs (revision 0) +++ Core/Gui/src/Core.Gui/Plugin/ImportInfo.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,172 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Base.IO; +using Core.Common.Util; +using Core.Gui.Properties; + +namespace Core.Gui.Plugin +{ + /// + /// Information for creating an importer for a particular data object. + /// + public class ImportInfo + { + /// + /// Gets or sets the data type associated with this import info. + /// + public Type DataType { get; set; } + + /// + /// Gets or sets the method used to create a . Function arguments: + /// + /// The data to import. + /// The file to import data from. + /// out - The created importer. + /// + /// + public Func CreateFileImporter { get; set; } + + /// + /// Gets or sets the method used to verify whether changes that are induced by the importer + /// are allowed. + /// + public Func VerifyUpdates { get; set; } + + /// + /// Gets or sets the method used to determine whether or not the import routine should be enabled. Function arguments: + /// + /// The data to import. + /// out - true if the import should be enabled, false otherwise. + /// + /// + public Func IsEnabled { get; set; } + + /// + /// Gets or sets the name of the import information. + /// + public string Name { get; set; } + + /// + /// Gets or sets the category of the import information. + /// + /// This should never return null. + public string Category { get; set; } = Resources.ImportInfo_Default_category; + + /// + /// Gets or sets the image of the import information. + /// + /// This should never return null. + public Image Image { get; set; } = Resources.brick; + + /// + /// Gets or sets the file filter generator of the import information used to make file filters. + /// + public FileFilterGenerator FileFilterGenerator { get; set; } + } + + /// + /// Information for creating an importer for a particular data object. + /// + /// The data type associated with this import info. + public class ImportInfo + { + /// + /// Gets the data type associated with this import info. + /// + public Type DataType + { + get + { + return typeof(TData); + } + } + + /// + /// Gets or sets the method used to create a . Function arguments: + /// + /// The data to import. + /// The path to the file to import from. + /// out - The created importer. + /// + /// + public Func CreateFileImporter { get; set; } + + /// + /// Gets or sets the method used to determine whether or not the import routine should be enabled. Function arguments: + /// + /// The data to import. + /// out - true if the import should be enabled, false otherwise. + /// + /// + public Func IsEnabled { get; set; } + + /// + /// Gets or sets the method used to verify whether changes that are induced by the importer + /// are allowed. + /// + public Func VerifyUpdates { get; set; } + + /// + /// Gets or sets the name of the import information. + /// + public string Name { get; set; } + + /// + /// Gets or sets the category of the import information. + /// + /// This should never return null. + public string Category { get; set; } = Resources.ImportInfo_Default_category; + + /// + /// Gets or sets the image of the import information. + /// + /// This should never return null. + public Image Image { get; set; } = Resources.brick; + + /// + /// Gets or sets the file filter generator of the import information used to make file filters. + /// + public FileFilterGenerator FileFilterGenerator { get; set; } + + /// + /// Performs an implicit conversion from to . + /// + /// The import information to convert. + /// The result of the conversion. + public static implicit operator ImportInfo(ImportInfo importInfo) + { + return new ImportInfo + { + DataType = importInfo.DataType, + CreateFileImporter = (data, path) => importInfo.CreateFileImporter?.Invoke((TData) data, path), + IsEnabled = data => importInfo.IsEnabled == null || importInfo.IsEnabled((TData) data), + VerifyUpdates = data => importInfo.VerifyUpdates == null || importInfo.VerifyUpdates((TData) data), + Name = importInfo.Name, + Category = importInfo.Category, + Image = importInfo.Image, + FileFilterGenerator = importInfo.FileFilterGenerator + }; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Plugin/PluginBase.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Plugin/PluginBase.cs (revision 0) +++ Core/Gui/src/Core.Gui/Plugin/PluginBase.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,141 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Linq; +using Core.Common.Controls.TreeView; +using Core.Gui.Helpers; + +namespace Core.Gui.Plugin +{ + /// + /// Template class for a plug-in definitions. + /// + public abstract class PluginBase : IDisposable + { + private IInquiryHelper inquiryHelper; + + /// + /// Gets or sets the gui. + /// + public virtual IGui Gui { get; set; } + + /// + /// Activates the plug-in. + /// + public virtual void Activate() {} + + /// + /// Deactivates the plug-in. + /// + public virtual void Deactivate() {} + + /// + /// Returns all instances provided by this plug-in. + /// + public virtual IEnumerable GetImportInfos() + { + yield break; + } + + /// + /// Returns all instances provided by this plug-in. + /// + public virtual IEnumerable GetUpdateInfos() + { + yield break; + } + + /// + /// Returns all instances provided by this plug-in. + /// + public virtual IEnumerable GetExportInfos() + { + yield break; + } + + /// + /// Returns all instances by of this plug-in. + /// + public virtual IEnumerable GetPropertyInfos() + { + return Enumerable.Empty(); + } + + /// + /// Returns all instances provided by this plug-in. + /// + public virtual IEnumerable GetViewInfos() + { + yield break; + } + + /// + /// Returns all instances provided by this plug-in. + /// + public virtual IEnumerable GetTreeNodeInfos() + { + yield break; + } + + /// + /// Gets the child data instances that have definitions of + /// some parent data object. + /// + /// The parent data object. + /// Sequence of child data. + public virtual IEnumerable GetChildDataWithViewDefinitions(object viewData) + { + yield break; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Gui = null; + } + } + + /// + /// Returns the . + /// + /// The . + /// Thrown when + /// is null. + protected IInquiryHelper GetInquiryHelper() + { + if (Gui == null) + { + throw new InvalidOperationException("Gui cannot be null"); + } + + return inquiryHelper ?? (inquiryHelper = new DialogBasedInquiryHelper(Gui.MainWindow)); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Plugin/PropertyInfo.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Plugin/PropertyInfo.cs (revision 0) +++ Core/Gui/src/Core.Gui/Plugin/PropertyInfo.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,147 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Gui.PropertyBag; + +namespace Core.Gui.Plugin +{ + /// + /// Information for creating object properties for a particular data object. + /// + public class PropertyInfo + { + /// + /// Initializes a new instance of the class. + /// + public PropertyInfo() + { + CreateInstance = o => + { + var properties = (IObjectProperties) Activator.CreateInstance(PropertyObjectType); + properties.Data = o; + return properties; + }; + } + + /// + /// Gets or sets the type of the data to create properties for. + /// + public Type DataType { get; set; } + + /// + /// Gets or sets the type of object properties to create. + /// + public Type PropertyObjectType { get; set; } + + /// + /// Gets or sets the optional function used to create a new property instance. + /// The function provided should guarantee that property + /// for the newly created property instance is set. + /// + /// + /// As an example, you could implement this as follows: + /// var propertyInfo = new PropertyInfo <Folder, ModelImplementationFolderProperties> + /// { + /// CreateInstance = o => new ModelImplementationFolderProperties + /// { + /// Data = o + /// } + /// }; + /// + public Func CreateInstance { get; set; } + } + + /// + /// Information for creating object properties for a particular data object. + /// + /// The type of the object to create object properties for. + /// The type of the object properties to create. + public class PropertyInfo where TProperty : IObjectProperties + { + /// + /// Initializes a new instance of the class. + /// + public PropertyInfo() + { + CreateInstance = o => + { + var properties = (TProperty) Activator.CreateInstance(PropertyObjectType); + properties.Data = o; + return properties; + }; + } + + /// + /// Gets the type of the data to create properties for. + /// + public Type DataType + { + get + { + return typeof(TObject); + } + } + + /// + /// Gets the type of object properties to create. + /// + public Type PropertyObjectType + { + get + { + return typeof(TProperty); + } + } + + /// + /// Gets or sets the optional function used to create a new property instance. + /// The function provided should guarantee that property + /// for the newly created property instance is set. + /// + /// + /// As an example, you could implement this as follows: + /// var propertyInfo = new PropertyInfo <Folder, ModelImplementationFolderProperties> + /// { + /// CreateInstance = o => new ModelImplementationFolderProperties + /// { + /// Data = o + /// } + /// }; + /// + public Func CreateInstance { get; set; } + + /// + /// Performs an implicit conversion from to . + /// + /// The property information to convert. + /// The result of the conversion. + public static implicit operator PropertyInfo(PropertyInfo propertyInfo) + { + return new PropertyInfo + { + DataType = typeof(TObject), + PropertyObjectType = typeof(TProperty), + CreateInstance = o => propertyInfo.CreateInstance((TObject) o) + }; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Plugin/UpdateInfo.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Plugin/UpdateInfo.cs (revision 0) +++ Core/Gui/src/Core.Gui/Plugin/UpdateInfo.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,185 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Base.IO; +using Core.Common.Util; +using Core.Gui.Properties; + +namespace Core.Gui.Plugin +{ + /// + /// Information for creating an importer for updating a particular data object. + /// + public class UpdateInfo + { + /// + /// Gets or sets the data type associated with this update info. + /// + public Type DataType { get; set; } + + /// + /// Gets or sets the method used to create a used to update data. + /// Function arguments: + /// + /// The data to import. + /// The file to import data from. + /// out - The created importer. + /// + /// + public Func CreateFileImporter { get; set; } + + /// + /// Gets or sets the method used to determine whether or not the update routine should be enabled. Function arguments: + /// + /// The data to update. + /// out - true if the update should be enabled, false otherwise. + /// + /// + public Func IsEnabled { get; set; } + + /// + /// Gets or sets the method used to verify whether changes that are induced by the importer + /// are allowed. + /// + public Func VerifyUpdates { get; set; } + + /// + /// Gets or sets the current path from which the current data was imported. + /// + public Func CurrentPath { get; set; } + + /// + /// Gets or sets the name of the update information. + /// + public string Name { get; set; } + + /// + /// Gets or sets the category of the update information. + /// + /// Should never return null. + public string Category { get; set; } = Resources.UpdateInfo_Default_category; + + /// + /// Gets or sets the image of the update information. + /// + /// Should never return null. + public Image Image { get; set; } = Resources.brick; + + /// + /// Gets or sets the file filter generator of the update information used to make file filters. + /// + public FileFilterGenerator FileFilterGenerator { get; set; } + } + + /// + /// Information for creating an importer for updating a particular data object. + /// + /// The data type associated with this update info. + public class UpdateInfo + { + /// + /// Gets the data type associated with this update info. + /// + public Type DataType + { + get + { + return typeof(TData); + } + } + + /// + /// Gets or sets the method used to create a used to update data. + /// Function arguments: + /// + /// The data to import. + /// The path to the file to import from. + /// out - The created importer. + /// + /// + public Func CreateFileImporter { get; set; } + + /// + /// Gets or sets the method used to determine whether or not the update routine should be enabled. Function arguments: + /// + /// The data to update. + /// out - true if the update should be enabled, false otherwise. + /// + /// + public Func IsEnabled { get; set; } + + /// + /// Gets or sets the method used to verify whether changes that are induced by the importer + /// are allowed. + /// + public Func VerifyUpdates { get; set; } + + /// + /// Gets or sets the current path from which the current data was imported. + /// + public Func CurrentPath { get; set; } + + /// + /// Gets or sets the name of the update information. + /// + public string Name { get; set; } + + /// + /// Gets or sets the category of the update information. + /// + /// Should never return null. + public string Category { get; set; } = Resources.UpdateInfo_Default_category; + + /// + /// Gets or sets the image of the update information. + /// + /// Should never return null. + public Image Image { get; set; } = Resources.brick; + + /// + /// Gets or sets the file filter generator of the update information used to make file filters. + /// + public FileFilterGenerator FileFilterGenerator { get; set; } + + /// + /// Performs an implicit conversion from to . + /// + /// The update information to convert. + /// The result of the conversion. + public static implicit operator UpdateInfo(UpdateInfo updateInfo) + { + return new UpdateInfo + { + DataType = updateInfo.DataType, + CreateFileImporter = (data, path) => updateInfo.CreateFileImporter?.Invoke((TData) data, path), + IsEnabled = data => updateInfo.IsEnabled == null || updateInfo.IsEnabled((TData) data), + VerifyUpdates = data => updateInfo.VerifyUpdates == null || updateInfo.VerifyUpdates((TData) data), + CurrentPath = data => updateInfo.CurrentPath?.Invoke((TData) data), + Name = updateInfo.Name, + Category = updateInfo.Category, + Image = updateInfo.Image, + FileFilterGenerator = updateInfo.FileFilterGenerator + }; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Plugin/ViewInfo.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Plugin/ViewInfo.cs (revision 0) +++ Core/Gui/src/Core.Gui/Plugin/ViewInfo.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,292 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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 Core.Common.Controls.Views; + +namespace Core.Gui.Plugin +{ + /// + /// Information for creating a view for a particular data object. + /// + public class ViewInfo + { + /// + /// Initializes a new instance of the class. + /// + public ViewInfo() + { + CreateInstance = o => (IView) Activator.CreateInstance(ViewType); + } + + /// + /// Gets or sets the data type associated with this view info. + /// + public Type DataType { get; set; } + + /// + /// Gets or sets the type of data used for the view. + /// + public Type ViewDataType { get; set; } + + /// + /// Gets or sets the type of the view. + /// + public Type ViewType { get; set; } + + /// + /// Gets or sets the description of the view. + /// + public string Description { get; set; } + + /// + /// Gets or sets the method used to determine the name for the view. Function arguments: + /// + /// The view to get a name for. + /// The data corresponding to this view info. + /// out - The name of the view. + /// + /// + public Func GetViewName { get; set; } + + /// + /// Gets or sets the icon of the view. + /// + public Image Image { get; set; } + + /// + /// Gets or sets the optional method for checking if this view info object can be + /// used for a given data object. Function arguments: + /// + /// Data for the view. + /// out - true is this view info can be used for the data, or false otherwise. + /// + /// + public Func AdditionalDataCheck { get; set; } + + /// + /// Gets or sets the optional method used to convert data from the type defined by + /// to the type defined by . Function Arguments: + /// + /// Original data. + /// out - The converted data to be used in the view. + /// + /// + public Func GetViewData { get; set; } + + /// + /// Gets or sets the optional method that performs additional actions after the + /// view has been created. Function arguments: + /// + /// The created view instance. + /// The data corresponding to this view info. + /// + /// + public Action AfterCreate { get; set; } + + /// + /// Gets or sets the optional method that allows for actions to be performed to + /// see if the view should be closed. Function arguments: + /// + /// View to close. + /// Data of the view. + /// out - true if the closing action was successful, false otherwise. + /// + /// + public Func CloseForData { get; set; } + + /// + /// Gets or sets the optional method that allows for the construction of the view. + /// Function arguments: + /// + /// The data corresponding to this view info. + /// The view to create. + /// + /// + /// This property needs to be set if no default constructor is available + /// for the view type. + public Func CreateInstance { get; set; } + + public override string ToString() + { + return DataType + " : " + ViewDataType + " : " + ViewType; + } + } + + /// + /// Information for creating a view for a particular data object. + /// + /// Data type associated with this view info. + /// Type of data used for the view. + /// Type of the view. + public class ViewInfo where TView : IView + { + /// + /// Initializes a new instance of the class. + /// + public ViewInfo() + { + CreateInstance = o => (TView) Activator.CreateInstance(ViewType); + } + + /// + /// Gets the data type associated with this view info. + /// + public Type DataType + { + get + { + return typeof(TData); + } + } + + /// + /// Gets the type of data used for the view. + /// + public Type ViewDataType + { + get + { + return typeof(TViewData); + } + } + + /// + /// Gets the type of the view. + /// + public Type ViewType + { + get + { + return typeof(TView); + } + } + + /// + /// Gets or sets the description of the view. + /// + public string Description { get; set; } + + /// + /// Gets or sets the method used to determine the name for the view. Function arguments: + /// + /// The view to get a name for. + /// The data corresponding to this view info. + /// out - The name of the view. + /// + /// + public Func GetViewName { get; set; } + + /// + /// Gets or sets the icon of the view. + /// + public Image Image { get; set; } + + /// + /// Gets or sets the optional method for checking if this view info object can be + /// used for a given data object. Function arguments: + /// + /// Data for the view. + /// out - true is this view info can be used for the data, or false otherwise. + /// + /// + public Func AdditionalDataCheck { get; set; } + + /// + /// Gets or sets the optional method used to convert data from the type defined by + /// to the type defined by . Function Arguments: + /// + /// Original data. + /// out - The converted data to be used in the view. + /// + /// + public Func GetViewData { get; set; } + + /// + /// Gets or sets the optional method that performs additional actions after the + /// view has been created. Function arguments: + /// + /// The created view instance. + /// The data corresponding to this view info. + /// + /// + public Action AfterCreate { get; set; } + + /// + /// Gets or sets the optional method that allows for actions to be performed to + /// see if the view should be closed. Function arguments: + /// + /// View to close. + /// Data of the view. + /// out - true if the closing action was successful, false otherwise. + /// + /// + public Func CloseForData { get; set; } + + /// + /// Gets or sets the optional method that allows for the construction of the view. + /// Function arguments: + /// + /// The data corresponding to this view info. + /// The view to create. + /// + /// + /// This property needs to be set if no default constructor is available + /// for the view type. + public Func CreateInstance { get; set; } + + /// + /// Performs an implicit conversion from to . + /// + /// The view information to convert. + /// The result of the conversion. + public static implicit operator ViewInfo(ViewInfo viewInfo) + { + return new ViewInfo + { + DataType = viewInfo.DataType, + ViewDataType = viewInfo.ViewDataType, + ViewType = viewInfo.ViewType, + Description = viewInfo.Description, + Image = viewInfo.Image, + AdditionalDataCheck = o => viewInfo.AdditionalDataCheck == null || viewInfo.AdditionalDataCheck((TData) o), + GetViewData = o => viewInfo.GetViewData != null ? viewInfo.GetViewData((TData) o) : o, + CloseForData = (v, o) => viewInfo.CloseForData != null && viewInfo.CloseForData((TView) v, o), + AfterCreate = (v, o) => viewInfo.AfterCreate?.Invoke((TView) v, (TData) o), + GetViewName = (v, o) => viewInfo.GetViewName?.Invoke((TView) v, (TData) o), + CreateInstance = o => viewInfo.CreateInstance((TData) o) + }; + } + + public override string ToString() + { + return DataType + " : " + ViewDataType + " : " + ViewType; + } + } + + /// + /// Information for creating a view for a particular data object. + /// + /// Data type associated with this view info. + /// Type of the view. + public class ViewInfo : ViewInfo where TView : IView {} +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Properties/AssemblyInfo.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Properties/AssemblyInfo.cs (revision 0) +++ Core/Gui/src/Core.Gui/Properties/AssemblyInfo.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,28 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("Core.Gui")] +[assembly: AssemblyProduct("Core.Gui")] +[assembly: InternalsVisibleTo("Core.Gui.Test")] +[assembly: InternalsVisibleTo("Core.Gui.TestUtil")] \ No newline at end of file Index: Core/Gui/src/Core.Gui/Properties/Resources.Designer.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Properties/Resources.Designer.cs (revision 0) +++ Core/Gui/src/Core.Gui/Properties/Resources.Designer.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,1586 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Core.Gui.Properties { + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Core.Gui.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Bezig met het afronden van huidige taak, daarna annuleren.... + /// + public static string ActivityProgressDialog_CancelActivities_Quit_after_finishing_current_activity { + get { + return ResourceManager.GetString("ActivityProgressDialog_CancelActivities_Quit_after_finishing_current_activity", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Taak {0} van {1}. + /// + public static string ActivityProgressDialog_OnShown_Executing_step_0_of_1 { + get { + return ResourceManager.GetString("ActivityProgressDialog_OnShown_Executing_step_0_of_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan niet meerdere instanties van Riskeer starten. Sluit eerst de andere instantie.. + /// + public static string App_ShutdownIfNotFirstInstance_Cannot_start_multiple_instances_of_Riskeer_Please_close_the_other_instance_first { + get { + return ResourceManager.GetString("App_ShutdownIfNotFirstInstance_Cannot_start_multiple_instances_of_Riskeer_Please_" + + "close_the_other_instance_first", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Riskeer versie {0} wordt gestart door {1}.... + /// + public static string App_Starting_Riskeer_version_0_by_user_0 { + get { + return ResourceManager.GetString("App_Starting_Riskeer_version_0_by_user_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Onbekende kritieke fout opgetreden.. + /// + public static string App_Unhandled_exception { + get { + return ResourceManager.GetString("App_Unhandled_exception", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap application_import_blue { + get { + object obj = ResourceManager.GetObject("application_import_blue", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + public static System.Drawing.Icon application_import_blue1 { + get { + object obj = ResourceManager.GetObject("application_import_blue1", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap application_view_list { + get { + object obj = ResourceManager.GetObject("application_view_list", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Logbestand kan niet worden geopend.. + /// + public static string ApplicationFeatureCommandHandler_OpenLogFileExternal_Unable_to_open_log_file { + get { + return ResourceManager.GetString("ApplicationFeatureCommandHandler_OpenLogFileExternal_Unable_to_open_log_file", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Het is niet mogelijk het logbestand te openen. In plaats hiervan wordt de folder waarin het logbestand staat geopend.. + /// + public static string ApplicationFeatureiCommandHandler_OpenLogFileExternal_Unable_to_open_log_file_Opening_log_file_directory_instead { + get { + return ResourceManager.GetString("ApplicationFeatureiCommandHandler_OpenLogFileExternal_Unable_to_open_log_file_Ope" + + "ning_log_file_directory_instead", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap arrow_000_medium { + get { + object obj = ResourceManager.GetObject("arrow_000_medium", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + public static System.Drawing.Icon arrow_000_medium_question_mark { + get { + object obj = ResourceManager.GetObject("arrow_000_medium_question_mark", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap brick { + get { + object obj = ResourceManager.GetObject("brick", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + public static System.Drawing.Icon bug_exclamation { + get { + object obj = ResourceManager.GetObject("bug_exclamation", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap Busy_indicator { + get { + object obj = ResourceManager.GetObject("Busy_indicator", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Alles i&nklappen. + /// + public static string Collapse_all { + get { + return ResourceManager.GetString("Collapse_all", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Klap dit element en alle onderliggende elementen in.. + /// + public static string Collapse_all_ToolTip { + get { + return ResourceManager.GetString("Collapse_all_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap CollapseAllIcon { + get { + object obj = ResourceManager.GetObject("CollapseAllIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Kan geen instanties maken van de benodigde objecten.. + /// + public static string ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories { + get { + return ResourceManager.GetString("ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen element in het contextmenu creëren zonder dat de data bekend is.. + /// + public static string ContextMenuItemFactory_Can_not_create_context_menu_items_without_data { + get { + return ResourceManager.GetString("ContextMenuItemFactory_Can_not_create_context_menu_items_without_data", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen element in het contextmenu creëren zonder dat de boom bekend is.. + /// + public static string ContextMenuItemFactory_Can_not_create_context_menu_items_without_tree_view_control { + get { + return ResourceManager.GetString("ContextMenuItemFactory_Can_not_create_context_menu_items_without_tree_view_contro" + + "l", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap CopyHS { + get { + object obj = ResourceManager.GetObject("CopyHS", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Kon eigenschap {0} van type {1} niet vinden.. + /// + public static string Could_not_find_property_0_on_type_1_ { + get { + return ResourceManager.GetString("Could_not_find_property_0_on_type_1_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nieuw project aanmaken is gestart.. + /// + public static string Creating_new_project_started { + get { + return ResourceManager.GetString("Creating_new_project_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nieuw project aanmaken is gelukt.. + /// + public static string Creating_new_project_successful { + get { + return ResourceManager.GetString("Creating_new_project_successful", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Verwij&deren.... + /// + public static string Delete { + get { + return ResourceManager.GetString("Delete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Verwijder dit element uit de boom.. + /// + public static string Delete_ToolTip { + get { + return ResourceManager.GetString("Delete_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ma&p leegmaken.... + /// + public static string DeleteChildren { + get { + return ResourceManager.GetString("DeleteChildren", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Verwijder alle onderliggende elementen van dit element.. + /// + public static string DeleteChildren_WithChildren_ToolTip { + get { + return ResourceManager.GetString("DeleteChildren_WithChildren_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Er zijn geen onderliggende elementen om te verwijderen.. + /// + public static string DeleteChildren_WithoutChildren_ToolTip { + get { + return ResourceManager.GetString("DeleteChildren_WithoutChildren_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap DeleteChildrenIcon { + get { + object obj = ResourceManager.GetObject("DeleteChildrenIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap DeleteIcon { + get { + object obj = ResourceManager.GetObject("DeleteIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to DynamicPropertyOrderEvaluationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {0}.. + /// + public static string DynamicPropertyOrderEvaluationMethod_incorrect_argument_count_must_be_one_string_argument_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicPropertyOrderEvaluationMethod_incorrect_argument_count_must_be_one_string_" + + "argument_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Argument van DynamicPropertyOrderEvaluationMethod moet van het type 'string' zijn. Klasse: {0}.. + /// + public static string DynamicPropertyOrderEvaluationMethod_must_have_string_argument_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicPropertyOrderEvaluationMethod_must_have_string_argument_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicPropertyOrderEvaluationMethod moet 'int' als 'return type' hebben. Klasse: {0}.. + /// + public static string DynamicPropertyOrderEvaluationMethod_must_return_int_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicPropertyOrderEvaluationMethod_must_return_int_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicPropertyOrderEvaluationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {0}.. + /// + public static string DynamicPropertyOrderEvaluationMethod_not_found_or_not_public_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicPropertyOrderEvaluationMethod_not_found_or_not_public_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slechts één DynamicPropertyOrderEvaluationMethod toegestaan per klasse: {0}.. + /// + public static string DynamicPropertyOrderEvaluationMethod_only_one_allowed_per_Class_0_ { + get { + return ResourceManager.GetString("DynamicPropertyOrderEvaluationMethod_only_one_allowed_per_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicReadOnlyValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {0}.. + /// + public static string DynamicReadOnlyValidationMethod_incorrect_argument_count_must_be_one_string_argument_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicReadOnlyValidationMethod_incorrect_argument_count_must_be_one_string_argum" + + "ent_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Argument van DynamicReadOnlyValidationMethod moet van het type 'string' zijn. Klasse: {0}.. + /// + public static string DynamicReadOnlyValidationMethod_must_have_string_argument_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicReadOnlyValidationMethod_must_have_string_argument_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicReadOnlyValidationMethod moet 'bool' als 'return type' hebben. Klasse: {0}.. + /// + public static string DynamicReadOnlyValidationMethod_must_return_bool_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicReadOnlyValidationMethod_must_return_bool_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicReadOnlyValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {0}.. + /// + public static string DynamicReadOnlyValidationMethod_not_found_or_not_public_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicReadOnlyValidationMethod_not_found_or_not_public_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slechts één DynamicReadOnlyValidationMethod toegestaan per klasse: {0}.. + /// + public static string DynamicReadOnlyValidationMethod_only_one_allowed_per_Class_0_ { + get { + return ResourceManager.GetString("DynamicReadOnlyValidationMethod_only_one_allowed_per_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicVisibleValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {0}.. + /// + public static string DynamicVisibleValidationMethod_incorrect_argument_count_must_be_one_string_argument_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicVisibleValidationMethod_incorrect_argument_count_must_be_one_string_argume" + + "nt_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Argument van DynamicVisibleValidationMethod moet van het type 'string' zijn. Klasse: {0}.. + /// + public static string DynamicVisibleValidationMethod_must_have_string_argument_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicVisibleValidationMethod_must_have_string_argument_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicVisibleValidationMethod moet 'bool' als 'return type' hebben. Klasse: {0}.. + /// + public static string DynamicVisibleValidationMethod_must_return_bool_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicVisibleValidationMethod_must_return_bool_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DynamicVisibleValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {0}.. + /// + public static string DynamicVisibleValidationMethod_not_found_or_not_public_on_Class_0_ { + get { + return ResourceManager.GetString("DynamicVisibleValidationMethod_not_found_or_not_public_on_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slechts één DynamicVisibleValidationMethod toegestaan per klasse: {0}.. + /// + public static string DynamicVisibleValidationMethod_only_one_allowed_per_Class_0_ { + get { + return ResourceManager.GetString("DynamicVisibleValidationMethod_only_one_allowed_per_Class_0_", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap error { + get { + object obj = ResourceManager.GetObject("error", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Opslaan van project is mislukt.. + /// + public static string ExceptionDialog_ButtonSaveProjectClick_Saving_project_failed { + get { + return ResourceManager.GetString("ExceptionDialog_ButtonSaveProjectClick_Saving_project_failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project is niet opgeslagen. + /// + public static string ExceptionDialog_ButtonSaveProjectClick_Saving_project_failed_caption { + get { + return ResourceManager.GetString("ExceptionDialog_ButtonSaveProjectClick_Saving_project_failed_caption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opslaan van project is gelukt.. + /// + public static string ExceptionDialog_ButtonSaveProjectClick_Successfully_saved_project { + get { + return ResourceManager.GetString("ExceptionDialog_ButtonSaveProjectClick_Successfully_saved_project", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project is opgeslagen. + /// + public static string ExceptionDialog_ButtonSaveProjectClick_Successfully_saved_project_caption { + get { + return ResourceManager.GetString("ExceptionDialog_ButtonSaveProjectClick_Successfully_saved_project_caption", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap exclamation { + get { + object obj = ResourceManager.GetObject("exclamation", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Alles ui&tklappen. + /// + public static string Expand_all { + get { + return ResourceManager.GetString("Expand_all", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Klap dit element en alle onderliggende elementen uit.. + /// + public static string Expand_all_ToolTip { + get { + return ResourceManager.GetString("Expand_all_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Aantal ({0}). + /// + public static string ExpandableArrayConverter_ConvertTo_Count_0_ { + get { + return ResourceManager.GetString("ExpandableArrayConverter_ConvertTo_Count_0_", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap ExpandAllIcon { + get { + object obj = ResourceManager.GetObject("ExpandAllIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to &Exporteren.... + /// + public static string Export { + get { + return ResourceManager.GetString("Export", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exporteer de gegevens naar een bestand.. + /// + public static string Export_ToolTip { + get { + return ResourceManager.GetString("Export_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap ExportIcon { + get { + object obj = ResourceManager.GetObject("ExportIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Algemeen. + /// + public static string ExportInfo_Default_category { + get { + return ResourceManager.GetString("ExportInfo_Default_category", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap folder { + get { + object obj = ResourceManager.GetObject("folder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to {0} (*.{1}). + /// + public static string GetItemName_Name_0_FileExtension_1 { + get { + return ResourceManager.GetString("GetItemName_Name_0_FileExtension_1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen 'IExportCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'IExportCommandHandler'.. + /// + public static string GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_export_handler { + get { + return ResourceManager.GetString("GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_export_ha" + + "ndler", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen 'ApplicationFeatureCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'ApplicationFeatureCommandHandler'.. + /// + public static string GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_gui { + get { + return ResourceManager.GetString("GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_gui", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen 'IImportCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'IImportCommandHandler'.. + /// + public static string GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_import_handler { + get { + return ResourceManager.GetString("GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_import_ha" + + "ndler", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen 'IUpdateCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'IUpdateCommandHandler'.. + /// + public static string GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_update_handler { + get { + return ResourceManager.GetString("GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_update_ha" + + "ndler", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen 'IViewCommands'-afhankelijk element in het contextmenu creëren zonder een 'IViewCommands'.. + /// + public static string GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_view_commands { + get { + return ResourceManager.GetString("GuiContextMenuItemFactory_Can_not_create_gui_context_menu_items_without_view_comm" + + "ands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kritieke fout opgetreden tijdens deactivering van de grafische interface plugin.. + /// + public static string GuiCore_ActivatePlugins_Exception_during_plugin_gui_deactivation { + get { + return ResourceManager.GetString("GuiCore_ActivatePlugins_Exception_during_plugin_gui_deactivation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slechts één instantie van de Riskeer grafische interface is toegestaan per proces. Zorg ervoor dat de vorige instantie correct opgeruimd is. 'Stack trace': {0}. + /// + public static string GuiCore_Only_a_single_instance_of_Riskeer_is_allowed_at_the_same_time_per_process_Make_sure_that_the_previous_instance_was_disposed_correctly_stack_trace_0 { + get { + return ResourceManager.GetString("GuiCore_Only_a_single_instance_of_Riskeer_is_allowed_at_the_same_time_per_process" + + "_Make_sure_that_the_previous_instance_was_disposed_correctly_stack_trace_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gestart in {0:f2} seconden.. + /// + public static string GuiCore_Run_Started_in_0_f2_sec { + get { + return ResourceManager.GetString("GuiCore_Run_Started_in_0_f2_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gebruiker heeft het opstarten onderbroken. Het programma wordt afgesloten.... + /// + public static string GuiCore_ShowSplashScreen_User_has_canceled_start_Exiting { + get { + return ResourceManager.GetString("GuiCore_ShowSplashScreen_User_has_canceled_start_Exiting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gegevens zijn geëxporteerd naar bestand '{0}'.. + /// + public static string GuiExportHandler_ExportItemUsingDialog_Data_exported_to_File_0 { + get { + return ResourceManager.GetString("GuiExportHandler_ExportItemUsingDialog_Data_exported_to_File_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exporteren van '{0}' is mislukt.. + /// + public static string GuiExportHandler_ExportItemUsingDialog_Export_of_DataType_0_failed { + get { + return ResourceManager.GetString("GuiExportHandler_ExportItemUsingDialog_Export_of_DataType_0_failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exporteren van '{0}' is gelukt.. + /// + public static string GuiExportHandler_ExportItemUsingDialog_Export_of_DataType_0_successful { + get { + return ResourceManager.GetString("GuiExportHandler_ExportItemUsingDialog_Export_of_DataType_0_successful", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exporteren van '{0}' is gestart.. + /// + public static string GuiExportHandler_ExportItemUsingDialog_Start_exporting_DataType_0_ { + get { + return ResourceManager.GetString("GuiExportHandler_ExportItemUsingDialog_Start_exporting_DataType_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fout. + /// + public static string GuiExportHandler_GetSupportedExporterForItemUsingDialog_Error { + get { + return ResourceManager.GetString("GuiExportHandler_GetSupportedExporterForItemUsingDialog_Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Riskeer kan de huidige selectie ({0}) niet exporteren.. + /// + public static string GuiExportHandler_GetSupportedExporterForItemUsingDialog_No_exporter_for_this_item_0_available { + get { + return ResourceManager.GetString("GuiExportHandler_GetSupportedExporterForItemUsingDialog_No_exporter_for_this_item" + + "_0_available", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Riskeer kan de huidige selectie niet exporteren.. + /// + public static string GuiExportHandler_GetSupportedExporterForItemUsingDialog_No_exporter_for_this_item_available { + get { + return ResourceManager.GetString("GuiExportHandler_GetSupportedExporterForItemUsingDialog_No_exporter_for_this_item" + + "_available", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kies wat u wilt exporteren. + /// + public static string GuiExportHandler_GetSupportedExportInfoUsingDialog_Select_exporter { + get { + return ResourceManager.GetString("GuiExportHandler_GetSupportedExportInfoUsingDialog_Select_exporter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kies wat u wilt importeren. + /// + public static string GuiImportHandler_GetSupportedImporterUsingDialog_Select_importer { + get { + return ResourceManager.GetString("GuiImportHandler_GetSupportedImporterUsingDialog_Select_importer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Importeren van gegevens is geannuleerd.. + /// + public static string GuiImportHandler_ImportItemsUsingDialog_Importing_cancelled { + get { + return ResourceManager.GetString("GuiImportHandler_ImportItemsUsingDialog_Importing_cancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Importeren van '{0}'. + /// + public static string GuiImportHandler_RunImportActivity_Importing_0_ { + get { + return ResourceManager.GetString("GuiImportHandler_RunImportActivity_Importing_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fout. + /// + public static string GuiImportHandler_SelectImportInfo_Error { + get { + return ResourceManager.GetString("GuiImportHandler_SelectImportInfo_Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Geen enkele 'Importer' is beschikbaar voor dit element.. + /// + public static string GuiImportHandler_SelectImportInfo_No_importer_available_for_this_item { + get { + return ResourceManager.GetString("GuiImportHandler_SelectImportInfo_No_importer_available_for_this_item", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Geen enkele 'Importer' is beschikbaar voor dit element ({0}).. + /// + public static string GuiImportHandler_SelectImportInfo_No_importer_available_for_this_item_0_ { + get { + return ResourceManager.GetString("GuiImportHandler_SelectImportInfo_No_importer_available_for_this_item_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fout. + /// + public static string GuiUpdateHandler_GetSupportedUpdaterForTargetType_Error { + get { + return ResourceManager.GetString("GuiUpdateHandler_GetSupportedUpdaterForTargetType_Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Geen enkele 'Updater' is beschikbaar voor dit element.. + /// + public static string GuiUpdateHandler_GetSupportedUpdaterForTargetType_No_updater_available_for_this_item { + get { + return ResourceManager.GetString("GuiUpdateHandler_GetSupportedUpdaterForTargetType_No_updater_available_for_this_i" + + "tem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Geen enkele 'Updater' is beschikbaar voor dit element ({0}).. + /// + public static string GuiUpdateHandler_GetSupportedUpdaterForTargetType_No_updater_available_for_this_item_0_ { + get { + return ResourceManager.GetString("GuiUpdateHandler_GetSupportedUpdaterForTargetType_No_updater_available_for_this_i" + + "tem_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kies wat u wilt bijwerken. + /// + public static string GuiUpdateHandler_GetSupportedUpdaterUsingDialog_Select_updater { + get { + return ResourceManager.GetString("GuiUpdateHandler_GetSupportedUpdaterUsingDialog_Select_updater", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bijwerken van '{0}'. + /// + public static string GuiUpdateHandler_RunUpdateActivity_Updating_0_ { + get { + return ResourceManager.GetString("GuiUpdateHandler_RunUpdateActivity_Updating_0_", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bijwerken van gegevens is geannuleerd.. + /// + public static string GuiUpdateHandler_UpdateItemsUsingDialog_Updating_cancelled { + get { + return ResourceManager.GetString("GuiUpdateHandler_UpdateItemsUsingDialog_Updating_cancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bijwerken van gegevens in '{0}' is geannuleerd.. + /// + public static string GuiUpdateHandler_UpdateItemsUsingDialog_Updating_from_Path_0_cancelled { + get { + return ResourceManager.GetString("GuiUpdateHandler_UpdateItemsUsingDialog_Updating_from_Path_0_cancelled", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap icon_clear_all_messages { + get { + object obj = ResourceManager.GetObject("icon_clear_all_messages", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to &Importeren.... + /// + public static string Import { + get { + return ResourceManager.GetString("Import", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Importeer de gegevens vanuit een bestand.. + /// + public static string Import_ToolTip { + get { + return ResourceManager.GetString("Import_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap ImportIcon { + get { + object obj = ResourceManager.GetObject("ImportIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Importeren gegevens. + /// + public static string ImportInfo_Default_category { + get { + return ResourceManager.GetString("ImportInfo_Default_category", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap information { + get { + object obj = ResourceManager.GetObject("information", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap key { + get { + object obj = ResourceManager.GetObject("key", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Project. + /// + public static string MainButtonBar_Project_DisplayName { + get { + return ResourceManager.GetString("MainButtonBar_Project_DisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Berichten. + /// + public static string Messages { + get { + return ResourceManager.GetString("Messages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Berichten. + /// + public static string MessageWindow_MessageWindow_Messages { + get { + return ResourceManager.GetString("MessageWindow_MessageWindow_Messages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Controleer logbestand voor meer informatie ("Bestand"->"Help"->"Log tonen").. + /// + public static string MessageWindowLogAppender_AppendToMessageWindow_Check_log_file_for_more_information_Home_Show_Log { + get { + return ResourceManager.GetString("MessageWindowLogAppender_AppendToMessageWindow_Check_log_file_for_more_informatio" + + "n_Home_Show_Log", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to &Openen. + /// + public static string Open { + get { + return ResourceManager.GetString("Open", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Open de gegevens in een nieuw documentvenster.. + /// + public static string Open_ToolTip { + get { + return ResourceManager.GetString("Open_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Openen. + /// + public static string OpenFileDialog_Title { + get { + return ResourceManager.GetString("OpenFileDialog_Title", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap OpenIcon { + get { + object obj = ResourceManager.GetObject("OpenIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Openen van project. + /// + public static string OpenProjectActivity_Open_project { + get { + return ResourceManager.GetString("OpenProjectActivity_Open_project", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initialiseren van leeg project. + /// + public static string OpenProjectActivity_ProgressTextStepName_InitializeEmptyProject { + get { + return ResourceManager.GetString("OpenProjectActivity_ProgressTextStepName_InitializeEmptyProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initialiseren van geopend project. + /// + public static string OpenProjectActivity_ProgressTextStepName_InitializeProject { + get { + return ResourceManager.GetString("OpenProjectActivity_ProgressTextStepName_InitializeProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Migreren van project. + /// + public static string OpenProjectActivity_ProgressTextStepName_MigrateProject { + get { + return ResourceManager.GetString("OpenProjectActivity_ProgressTextStepName_MigrateProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inlezen van project. + /// + public static string OpenProjectActivity_ProgressTextStepName_ReadProject { + get { + return ResourceManager.GetString("OpenProjectActivity_ProgressTextStepName_ReadProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Projectverkenner. + /// + public static string ProjectExplorer_DisplayName { + get { + return ResourceManager.GetString("ProjectExplorer_DisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap ProjectExplorerIcon { + get { + object obj = ResourceManager.GetObject("ProjectExplorerIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap ProjectIcon { + get { + object obj = ResourceManager.GetObject("ProjectIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Ei&genschappen. + /// + public static string Properties { + get { + return ResourceManager.GetString("Properties", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Eigenschappen. + /// + public static string Properties_Title { + get { + return ResourceManager.GetString("Properties_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toon de eigenschappen in het Eigenschappenpaneel.. + /// + public static string Properties_ToolTip { + get { + return ResourceManager.GetString("Properties_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap PropertiesHS { + get { + object obj = ResourceManager.GetObject("PropertiesHS", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap PropertiesPanelIcon { + get { + object obj = ResourceManager.GetObject("PropertiesPanelIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Alfabetisch. + /// + public static string PropertyGridView_Order_Alphabetically { + get { + return ResourceManager.GetString("PropertyGridView_Order_Alphabetically", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gecategoriseerd. + /// + public static string PropertyGridView_Order_Categorized { + get { + return ResourceManager.GetString("PropertyGridView_Order_Categorized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kan geen 'PropertyResolver' maken zonder een lijst van 'PropertyInfo'.. + /// + public static string PropertyResolver_PropertyResolver_Cannot_create_PropertyResolver_without_list_of_PropertyInfo { + get { + return ResourceManager.GetString("PropertyResolver_PropertyResolver_Cannot_create_PropertyResolver_without_list_of_" + + "PropertyInfo", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap RefreshIcon { + get { + object obj = ResourceManager.GetObject("RefreshIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to &Hernoemen. + /// + public static string Rename { + get { + return ResourceManager.GetString("Rename", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wijzig de naam van dit element.. + /// + public static string Rename_ToolTip { + get { + return ResourceManager.GetString("Rename_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap RenameIcon { + get { + object obj = ResourceManager.GetObject("RenameIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + public static System.Drawing.Icon Riskeer { + get { + object obj = ResourceManager.GetObject("Riskeer", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized string similar to Opslaan als. + /// + public static string SaveFileDialog_Title { + get { + return ResourceManager.GetString("SaveFileDialog_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Initialiseren van opgeslagen project. + /// + public static string SaveProjectActivity_ProgressTextStepName_InitializeSavedProject { + get { + return ResourceManager.GetString("SaveProjectActivity_ProgressTextStepName_InitializeSavedProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project opslaan. + /// + public static string SaveProjectActivity_ProgressTextStepName_SavingProject { + get { + return ResourceManager.GetString("SaveProjectActivity_ProgressTextStepName_SavingProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voorbereidingen opslaan. + /// + public static string SaveProjectActivity_ProgressTextStepName_StagingProject { + get { + return ResourceManager.GetString("SaveProjectActivity_ProgressTextStepName_StagingProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opslaan van bestaand project. + /// + public static string SaveProjectActivity_Save_existing_project { + get { + return ResourceManager.GetString("SaveProjectActivity_Save_existing_project", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opslaan van project. + /// + public static string SaveProjectActivity_Save_project { + get { + return ResourceManager.GetString("SaveProjectActivity_Save_project", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fout. + /// + public static string SelectItemDialog_buttonOk_Click_Error { + get { + return ResourceManager.GetString("SelectItemDialog_buttonOk_Click_Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kies een type. + /// + public static string SelectItemDialog_buttonOk_Click_Please_select_an_item { + get { + return ResourceManager.GetString("SelectItemDialog_buttonOk_Click_Please_select_an_item", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to - (Standaard). + /// + public static string SelectViewDialog_listBox_DrawItem_Default { + get { + return ResourceManager.GetString("SelectViewDialog_listBox_DrawItem_Default", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Website. + /// + public static string SplashScreen_SupportEmail { + get { + return ResourceManager.GetString("SplashScreen_SupportEmail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Telefoon. + /// + public static string SplashScreen_SupportPhoneNumber { + get { + return ResourceManager.GetString("SplashScreen_SupportPhoneNumber", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voor vragen: Helpdesk Water.. + /// + public static string SplashScreen_SupportTitle { + get { + return ResourceManager.GetString("SplashScreen_SupportTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Versie. + /// + public static string SplashScreen_Version { + get { + return ResourceManager.GetString("SplashScreen_Version", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project afsluiten. + /// + public static string StorageCommandHandler_ClosingProject_Title { + get { + return ResourceManager.GetString("StorageCommandHandler_ClosingProject_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nieuw project aanmaken is geannuleerd.. + /// + public static string StorageCommandHandler_NewProject_Creating_new_project_canceled { + get { + return ResourceManager.GetString("StorageCommandHandler_NewProject_Creating_new_project_canceled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sla wijzigingen in het project op: {0}?. + /// + public static string StorageCommandHandler_OpenSaveOrDiscardProjectDialog_SaveChangesToProject_0 { + get { + return ResourceManager.GetString("StorageCommandHandler_OpenSaveOrDiscardProjectDialog_SaveChangesToProject_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to &Bijwerken.... + /// + public static string Update { + get { + return ResourceManager.GetString("Update", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Werk de geïmporteerde gegevens bij met nieuwe gegevens vanuit een bestand.. + /// + public static string Update_ToolTip { + get { + return ResourceManager.GetString("Update_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bijwerken gegevens. + /// + public static string UpdateInfo_Default_category { + get { + return ResourceManager.GetString("UpdateInfo_Default_category", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Over. + /// + public static string ViewStateBar_About_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_About_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Grafiek. + /// + public static string ViewStateBar_Chart_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_Chart_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Afsluiten. + /// + public static string ViewStateBar_Exit_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_Exit_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kaart. + /// + public static string ViewStateBar_Map_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_Map_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Berichten. + /// + public static string ViewStateBar_Messages_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_Messages_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gebruikershandleiding Openen. + /// + public static string ViewStateBar_OpenManual_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_OpenManual_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Projectverkenner. + /// + public static string ViewStateBar_ProjectExplorer_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_ProjectExplorer_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Eigenschappen. + /// + public static string ViewStateBar_Properties_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_Properties_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log Tonen. + /// + public static string ViewStateBar_ShowLog_ToolTip { + get { + return ResourceManager.GetString("ViewStateBar_ShowLog_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + public static System.Drawing.Icon warning { + get { + object obj = ResourceManager.GetObject("warning", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized string similar to Nieuw. + /// + public static string WindowCommands_New_ToolTip { + get { + return ResourceManager.GetString("WindowCommands_New_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Openen. + /// + public static string WindowCommands_Open_ToolTip { + get { + return ResourceManager.GetString("WindowCommands_Open_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opslaan. + /// + public static string WindowCommands_Save_ToolTip { + get { + return ResourceManager.GetString("WindowCommands_Save_ToolTip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opslaan Als. + /// + public static string WindowCommands_SaveAs_ToolTip { + get { + return ResourceManager.GetString("WindowCommands_SaveAs_ToolTip", resourceCulture); + } + } + } +} Index: Core/Gui/src/Core.Gui/Properties/Resources.resx =================================================================== diff -u --- Core/Gui/src/Core.Gui/Properties/Resources.resx (revision 0) +++ Core/Gui/src/Core.Gui/Properties/Resources.resx (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,607 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Eigenschappen + + + + Nieuw + + + Kan niet meerdere instanties van Riskeer starten. Sluit eerst de andere instantie. + + + ..\Resources\exclamation.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Onbekende kritieke fout opgetreden. + + + Opslaan + + + Kritieke fout opgetreden tijdens deactivering van de grafische interface plugin. + + + Nieuw project aanmaken is gestart. + + + Berichten + + + ..\Resources\application_view_list.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Het is niet mogelijk het logbestand te openen. In plaats hiervan wordt de folder waarin het logbestand staat geopend. + + + ../Resources/DeleteHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Geen enkele 'Importer' is beschikbaar voor dit element ({0}). + + + Geen enkele 'Updater' is beschikbaar voor dit element ({0}). + + + ..\Resources\CopyHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\PropertiesHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Opslaan Als + + + - (Standaard) + + + Riskeer versie {0} wordt gestart door {1}... + + + Berichten + + + Nieuw project aanmaken is gelukt. + + + Gebruikershandleiding Openen + + + ..\Resources\folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Gestart in {0:f2} seconden. + + + ..\Resources\application_import_blue.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\application_import_blue.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Openen + + + Gebruiker heeft het opstarten onderbroken. Het programma wordt afgesloten... + + + Over + + + ..\Resources\error.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Fout + + + Openen + + + Logbestand kan niet worden geopend. + + + Kies een type + + + Controleer logbestand voor meer informatie ("Bestand"->"Help"->"Log tonen"). + + + Eigenschappen + + + ../Resources/brick.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Geen enkele 'Importer' is beschikbaar voor dit element. + + + Geen enkele 'Updater' is beschikbaar voor dit element. + + + Afsluiten + + + ..\Resources\information.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Slechts één instantie van de Riskeer grafische interface is toegestaan per proces. Zorg ervoor dat de vorige instantie correct opgeruimd is. 'Stack trace': {0} + + + Log Tonen + + + Berichten + + + Importeren gegevens + + + Bijwerken gegevens + + + ..\Resources\icon_clear_all_messages.PNG;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Aantal ({0}) + + + Exporteren van '{0}' is mislukt. + + + Exporteren van '{0}' is gelukt. + + + Exporteren van '{0}' is gestart. + + + Riskeer kan de huidige selectie niet exporteren. + + + Riskeer kan de huidige selectie ({0}) niet exporteren. + + + Versie + + + &Exporteren... + + + Exporteer de gegevens naar een bestand. + + + ..\resources\table-export.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + &Importeren... + + + ..\resources\table-import.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Importeer de gegevens vanuit een bestand. + + + Toon de eigenschappen in het Eigenschappenpaneel. + + + Ei&genschappen + + + ..\resources\arrow-stop-090.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Alles i&nklappen + + + Klap dit element en alle onderliggende elementen in. + + + ..\resources\arrow-stop-270.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Alles ui&tklappen + + + Klap dit element en alle onderliggende elementen uit. + + + Kan geen 'ApplicationFeatureCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'ApplicationFeatureCommandHandler'. + + + Kan geen element in het contextmenu creëren zonder dat de data bekend is. + + + Kan geen element in het contextmenu creëren zonder dat de boom bekend is. + + + &Openen + + + ..\resources\arrow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Open de gegevens in een nieuw documentvenster. + + + ..\Resources\Busy indicator.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Taak {0} van {1} + + + Bezig met het afronden van huidige taak, daarna annuleren... + + + ..\Resources\arrow-000-medium.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Verwij&deren... + + + Verwijder dit element uit de boom. + + + Alfabetisch + + + Gecategoriseerd + + + Kan geen 'PropertyResolver' maken zonder een lijst van 'PropertyInfo'. + + + Kan geen instanties maken van de benodigde objecten. + + + Fout + + + Fout + + + ..\Resources\arrow-000-medium-question-mark.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\key.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + &Hernoemen + + + Wijzig de naam van dit element. + + + ..\resources\textfield_rename.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Kon eigenschap {0} van type {1} niet vinden. + + + DynamicReadOnlyValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {0}. + + + Argument van DynamicReadOnlyValidationMethod moet van het type 'string' zijn. Klasse: {0}. + + + DynamicReadOnlyValidationMethod moet 'bool' als 'return type' hebben. Klasse: {0}. + + + DynamicReadOnlyValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {0}. + + + Slechts één DynamicReadOnlyValidationMethod toegestaan per klasse: {0}. + + + DynamicVisibleValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {0}. + + + Argument van DynamicVisibleValidationMethod moet van het type 'string' zijn. Klasse: {0}. + + + DynamicVisibleValidationMethod moet 'bool' als 'return type' hebben. Klasse: {0}. + + + DynamicVisibleValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {0}. + + + Slechts één DynamicVisibleValidationMethod toegestaan per klasse: {0}. + + + DynamicPropertyOrderEvaluationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {0}. + + + Slechts één DynamicPropertyOrderEvaluationMethod toegestaan per klasse: {0}. + + + DynamicPropertyOrderEvaluationMethod moet 'int' als 'return type' hebben. Klasse: {0}. + + + DynamicPropertyOrderEvaluationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {0}. + + + Argument van DynamicPropertyOrderEvaluationMethod moet van het type 'string' zijn. Klasse: {0}. + + + Kan geen 'IImportCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'IImportCommandHandler'. + + + Kan geen 'IExportCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'IExportCommandHandler'. + + + Kan geen 'IUpdateCommandHandler'-afhankelijk element in het contextmenu creëren zonder een 'IUpdateCommandHandler'. + + + Kan geen 'IViewCommands'-afhankelijk element in het contextmenu creëren zonder een 'IViewCommands'. + + + Website + + + Telefoon + + + Voor vragen: Helpdesk Water. + + + Sla wijzigingen in het project op: {0}? + + + Project afsluiten + + + Nieuw project aanmaken is geannuleerd. + + + Fout + + + ..\Resources\project-16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Kies wat u wilt exporteren + + + Kies wat u wilt importeren + + + Kies wat u wilt bijwerken + + + Opslaan als + + + ..\resources\broom.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Ma&p leegmaken... + + + Verwijder alle onderliggende elementen van dit element. + + + Er zijn geen onderliggende elementen om te verwijderen. + + + &Bijwerken... + + + Werk de geïmporteerde gegevens bij met nieuwe gegevens vanuit een bestand. + + + ..\resources\table_refresh.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Bijwerken van gegevens in '{0}' is geannuleerd. + + + Importeren van gegevens is geannuleerd. + + + Openen van project + + + Migreren van project + + + Inlezen van project + + + Initialiseren van geopend project + + + Initialiseren van leeg project + + + Opslaan van bestaand project + + + Opslaan van project + + + Initialiseren van opgeslagen project + + + Voorbereidingen opslaan + + + Project opslaan + + + Algemeen + + + Bijwerken van gegevens is geannuleerd. + + + ..\Resources\bug-exclamation.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Opslaan van project is mislukt. + + + Project is niet opgeslagen + + + Opslaan van project is gelukt. + + + Project is opgeslagen + + + Importeren van '{0}' + + + Bijwerken van '{0}' + + + {0} (*.{1}) + + + ..\Resources\Riskeer.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Gegevens zijn geëxporteerd naar bestand '{0}'. + + + ..\Resources\warning.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Project + + + Projectverkenner + + + Kaart + + + Grafiek + + + Projectverkenner + + + ..\Resources\project_explorer.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\properties_panel.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/PropertyBag/DynamicPropertyBag.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/PropertyBag/DynamicPropertyBag.cs (revision 0) +++ Core/Gui/src/Core.Gui/PropertyBag/DynamicPropertyBag.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,196 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Linq; +using System.Reflection; +using Core.Gui.Attributes; +using Core.Gui.Forms.PropertyGridView; + +namespace Core.Gui.PropertyBag +{ + /// + /// Defines a custom type descriptor for an object to be used as view-model for . + /// It processes the special attributes defined in Core.Gui.Attributes + /// to dynamically affect property order or adding/removing . + /// + /// This class makes sure the following special attributes on properties are processed: + /// + /// + /// + /// + /// + /// + /// Worth mentioning is the fact that, when specified both, the + /// overrules the . + /// + public class DynamicPropertyBag : ICustomTypeDescriptor + { + /// + /// Creates a new instance of , wrapping another + /// object and exposing properties for that object. + /// + /// The object to be wrapped. + /// Thrown when + /// is null. + public DynamicPropertyBag(object propertyObject) + { + if (propertyObject == null) + { + throw new ArgumentNullException(nameof(propertyObject)); + } + + var properties = new HashSet(); + foreach (PropertyInfo propertyInfo in propertyObject.GetType().GetProperties() + .OrderBy(x => x.MetadataToken)) + { + properties.Add(new PropertySpec(propertyInfo)); + } + + Properties = properties; + WrappedObject = propertyObject; + } + + /// + /// Gets the set of properties contained within this . + /// + public IEnumerable Properties { get; } + + /// + /// Gets the object wrapped inside this . + /// + public object WrappedObject { get; } + + public override string ToString() + { + return WrappedObject.ToString(); + } + + #region ICustomTypeDescriptor explicit interface definitions + + #region Implementations delegated to System.ComponentModel.TypeDescriptor + + public AttributeCollection GetAttributes() + { + return TypeDescriptor.GetAttributes(this, true); + } + + public string GetClassName() + { + return TypeDescriptor.GetClassName(this, true); + } + + public string GetComponentName() + { + return TypeDescriptor.GetComponentName(this, true); + } + + public TypeConverter GetConverter() + { + return TypeDescriptor.GetConverter(this, true); + } + + public EventDescriptor GetDefaultEvent() + { + return TypeDescriptor.GetDefaultEvent(this, true); + } + + public EventDescriptorCollection GetEvents() + { + return TypeDescriptor.GetEvents(this, true); + } + + public EventDescriptorCollection GetEvents(Attribute[] attributes) + { + return TypeDescriptor.GetEvents(this, attributes, true); + } + + public object GetEditor(Type editorBaseType) + { + return TypeDescriptor.GetEditor(this, editorBaseType, true); + } + + #endregion + + public PropertyDescriptor GetDefaultProperty() + { + return Properties.Any() ? new PropertySpecDescriptor(Properties.First(), WrappedObject) : null; + } + + public PropertyDescriptorCollection GetProperties() + { + return GetProperties(new Attribute[0]); + } + + public PropertyDescriptorCollection GetProperties(Attribute[] attributes) + { + IEnumerable propertyDescriptorsToReturn = Properties.Select(p => new PropertySpecDescriptor(p, WrappedObject)) + .Where(t => ShouldDescriptorBeReturned(t, attributes)); + + PropertyDescriptor[] propertySpecDescriptors = OrderPropertyDescriptors(propertyDescriptorsToReturn); + return new PropertyDescriptorCollection(propertySpecDescriptors); + } + + private PropertyDescriptor[] OrderPropertyDescriptors(IEnumerable propertyDescriptorsToReturn) + { + var unorderedProperties = new List(); + var propertiesWithOrdering = new List>(); + + foreach (PropertyDescriptor pd in propertyDescriptorsToReturn) + { + PropertyOrderAttribute propertyOrderAttribute = pd.Attributes.OfType().FirstOrDefault(); + if (propertyOrderAttribute != null) + { + propertiesWithOrdering.Add(Tuple.Create(propertyOrderAttribute.Order, pd)); + continue; + } + + DynamicPropertyOrderAttribute dynamicPropertyOrderAttribute = pd.Attributes.OfType().FirstOrDefault(); + if (dynamicPropertyOrderAttribute != null) + { + propertiesWithOrdering.Add(Tuple.Create(DynamicPropertyOrderAttribute.PropertyOrder(WrappedObject, pd.Name), pd)); + continue; + } + + unorderedProperties.Add(pd); + } + + IEnumerable orderedProperties = propertiesWithOrdering.OrderBy(p => p.Item1).Select(p => p.Item2); + + return orderedProperties.Concat(unorderedProperties).ToArray(); + } + + private static bool ShouldDescriptorBeReturned(PropertyDescriptor propertySpecDescriptor, IEnumerable attributesFilter) + { + BrowsableAttribute browsableAttribute = attributesFilter.OfType().FirstOrDefault(); + return browsableAttribute == null || propertySpecDescriptor.IsBrowsable == browsableAttribute.Browsable; + } + + public object GetPropertyOwner(PropertyDescriptor pd) + { + return WrappedObject; + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/PropertyBag/IObjectProperties.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/PropertyBag/IObjectProperties.cs (revision 0) +++ Core/Gui/src/Core.Gui/PropertyBag/IObjectProperties.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,41 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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; + +namespace Core.Gui.PropertyBag +{ + /// + /// Interface for object properties. + /// + public interface IObjectProperties + { + /// + /// Fired when the property grid should be refreshed. + /// + event EventHandler RefreshRequired; + + /// + /// Gets or sets the data of the object properties. + /// + object Data { get; set; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/PropertyBag/ObjectProperties.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/PropertyBag/ObjectProperties.cs (revision 0) +++ Core/Gui/src/Core.Gui/PropertyBag/ObjectProperties.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,58 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; + +namespace Core.Gui.PropertyBag +{ + /// + /// Base class for object properties with data of type . + /// + /// Type of . + public class ObjectProperties : IObjectProperties + { + protected T data; + + public event EventHandler RefreshRequired; + + [Browsable(false)] + public object Data + { + get + { + return data; + } + set + { + data = (T) value; + } + } + + /// + /// Method for raising . + /// + protected void OnRefreshRequired() + { + RefreshRequired?.Invoke(this, new EventArgs()); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/PropertyBag/PropertySpec.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/PropertyBag/PropertySpec.cs (revision 0) +++ Core/Gui/src/Core.Gui/PropertyBag/PropertySpec.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,211 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Collections.ObjectModel; +using System.ComponentModel; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using log4net; + +namespace Core.Gui.PropertyBag +{ + /// + /// This class represents a single property. + /// + public class PropertySpec + { + private static readonly ILog log = LogManager.GetLogger(typeof(PropertySpec)); + private readonly PropertyInfo propertyInfo; + + /// + /// Initializes a new instance of the class for a given + /// property meta-data object. + /// + /// The property information. + /// Thrown when is + /// an index property. + /// Thrown when is null. + public PropertySpec(PropertyInfo propertyInfo) + { + if (propertyInfo == null) + { + throw new ArgumentNullException(nameof(propertyInfo)); + } + + if (propertyInfo.GetIndexParameters().Length > 0) + { + throw new ArgumentException(@"Index properties are not allowed.", nameof(propertyInfo)); + } + + this.propertyInfo = propertyInfo; + Name = propertyInfo.Name; + TypeName = propertyInfo.PropertyType.AssemblyQualifiedName; + + List attributeList = Attribute.GetCustomAttributes(propertyInfo, true).ToList(); + if (propertyInfo.GetSetMethod() == null) + { + attributeList.Add(new ReadOnlyAttribute(true)); + } + + Attributes = new ReadOnlyCollection(attributeList); + } + + /// + /// Gets or sets a collection of additional s for this property. + /// This can be used to specify attributes beyond those supported intrinsically by the + /// class, such as + /// and . + /// + public ReadOnlyCollection Attributes { get; } + + /// + /// Gets the name of the property. + /// + public string Name { get; } + + /// + /// Gets the fully qualified name of the type of this property. + /// + public string TypeName { get; } + + /// + /// Sets the property represented by this instance of some object instance. + /// + /// The instance to be updated. + /// The new value for the property. + /// Thrown when + /// + /// Represented property is an index-property. + /// does not match the target type. + /// Property is an instance property but is null. + /// is of incorrect type. + /// An error occurred while setting the property value. The + /// property indicates the reason for the error. + /// + /// Calling this method while property + /// has no setter. + /// Calling the method resulted in an exception. + /// Thrown when is null + /// or the method is not defined on . + public void SetValue(object instance, object newValue) + { + MethodInfo setMethodInfo = propertyInfo.GetSetMethod(); + if (setMethodInfo == null) + { + throw new InvalidOperationException("Property lacks public setter!"); + } + + setMethodInfo.Invoke(instance, new[] + { + newValue + }); + } + + /// + /// Gets the property value represented by this instance of some object instance. + /// + /// The instance that holds the property to be retrieved. + /// The property value on . + /// Thrown when + /// + /// Represented property is an index-property. + /// does not match the target type. + /// Property is an instance property but is null. + /// An error occurred while setting the property value. The + /// property indicates the reason for the error. + /// + /// Thrown when calling this method while + /// property has no getter. + public object GetValue(object instance) + { + MethodInfo getMethodInfo = propertyInfo.GetGetMethod(); + if (getMethodInfo == null) + { + throw new InvalidOperationException("Property lacks public getter!"); + } + + try + { + return getMethodInfo.Invoke(instance, new object[0]); + } + catch (TargetException e) + { + object type = instance?.GetType(); + string message = string.Format(CultureInfo.CurrentCulture, + "Are you calling GetValue on the correct instance? Expected '{0}', but was '{1}'", + propertyInfo.DeclaringType, type); + throw new ArgumentException(message, nameof(instance), e); + } + catch (TargetInvocationException e) + { + throw new ArgumentException(@"Something went wrong while getting property; Check InnerException for more information.", + nameof(instance), e); + } + } + + /// + /// Determines whether the captured property is decorated with + /// that is configured to use . + /// + /// Returns true if a is declared using + /// , false if no match has been found or when + /// the type converter inherits from . + /// Custom implementations of is + /// likely to have behavior that Core.Gui namespace cannot account for. As + /// such those properties will be considered not having the expandable object type converter. + public bool IsNonCustomExpandableObjectProperty() + { + var typeConverterAttribute = (TypeConverterAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(TypeConverterAttribute), true); + if (typeConverterAttribute != null) + { + try + { + Type type = Type.GetType(typeConverterAttribute.ConverterTypeName); + if (type != null && typeof(ExpandableObjectConverter) == type) + { + return true; + } + } + catch (Exception e) + { + if (e is TargetInvocationException + || e is ArgumentException + || e is TypeLoadException + || e is FileLoadException + || e is BadImageFormatException) + { + log.DebugFormat("Unable to find TypeConverter of type '{0}", typeConverterAttribute.ConverterTypeName); + } + else + { + throw; // Not expected exception -> Fail fast + } + } + } + + return false; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/PropertyBag/PropertySpecDescriptor.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/PropertyBag/PropertySpecDescriptor.cs (revision 0) +++ Core/Gui/src/Core.Gui/PropertyBag/PropertySpecDescriptor.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,141 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Linq; +using Core.Gui.Attributes; + +namespace Core.Gui.PropertyBag +{ + /// + /// A that works for properties captured in a + /// and handles Dynamic attributes. + /// + /// The following dynamic attributes are supported: + /// + /// + /// + /// + public class PropertySpecDescriptor : PropertyDescriptor + { + private readonly PropertySpec item; + private readonly object instance; + + /// + /// Initializes a new instance of the class + /// for a given . + /// + /// The property spec. + /// The instance which has the property captured in . + /// Thrown when + /// is null. + public PropertySpecDescriptor(PropertySpec propertySpec, object instance) + : base(ValidateNotNull(propertySpec).Name, propertySpec.Attributes.ToArray()) + { + item = propertySpec; + this.instance = instance; + } + + public override Type ComponentType + { + get + { + return item.GetType(); + } + } + + public override bool IsReadOnly + { + get + { + if (Attributes.Matches(new DynamicReadOnlyAttribute())) + { + return DynamicReadOnlyAttribute.IsReadOnly(instance, item.Name); + } + + return Attributes.Matches(ReadOnlyAttribute.Yes); + } + } + + public override bool IsBrowsable + { + get + { + if (Attributes.Matches(new DynamicVisibleAttribute())) + { + return DynamicVisibleAttribute.IsVisible(instance, item.Name); + } + + return !Attributes.Matches(BrowsableAttribute.No); + } + } + + public override Type PropertyType + { + get + { + return Type.GetType(item.TypeName); + } + } + + public override bool CanResetValue(object component) + { + return false; + } + + public override void ResetValue(object component) + { + throw new InvalidOperationException("Do not call 'ResetValue' if 'CanResetValue(object)' returns false."); + } + + public override object GetValue(object component) + { + object propertyValue = item.GetValue(component); + if (item.IsNonCustomExpandableObjectProperty()) + { + return new DynamicPropertyBag(propertyValue); + } + + return propertyValue; + } + + public override void SetValue(object component, object value) + { + item.SetValue(component, value); + } + + public override bool ShouldSerializeValue(object component) + { + return false; + } + + private static PropertySpec ValidateNotNull(PropertySpec propertySpec) + { + if (propertySpec == null) + { + throw new ArgumentNullException(nameof(propertySpec)); + } + + return propertySpec; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/PropertyBag/ReadOnlyPropertyDescriptorDecorator.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/PropertyBag/ReadOnlyPropertyDescriptorDecorator.cs (revision 0) +++ Core/Gui/src/Core.Gui/PropertyBag/ReadOnlyPropertyDescriptorDecorator.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,177 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; + +namespace Core.Gui.PropertyBag +{ + /// + /// A decorator that forces + /// to true regardless of the wrapped . + /// + public class ReadOnlyPropertyDescriptorDecorator : PropertyDescriptor + { + private readonly PropertyDescriptor wrappedPropertyDescriptor; + + /// + /// Initializes a new instance of the class. + /// + /// The property descriptor to be wrapped. + public ReadOnlyPropertyDescriptorDecorator(PropertyDescriptor propertyDescriptor) : base(propertyDescriptor) + { + wrappedPropertyDescriptor = propertyDescriptor; + } + + public override bool IsReadOnly + { + get + { + return true; + } + } + + #region Methods and Properties delegates to wrapped property descriptor + + public override bool CanResetValue(object component) + { + return wrappedPropertyDescriptor.CanResetValue(component); + } + + public override object GetValue(object component) + { + return wrappedPropertyDescriptor.GetValue(component); + } + + public override void ResetValue(object component) + { + wrappedPropertyDescriptor.ResetValue(component); + } + + public override void SetValue(object component, object value) + { + wrappedPropertyDescriptor.SetValue(component, value); + } + + public override bool ShouldSerializeValue(object component) + { + return wrappedPropertyDescriptor.ShouldSerializeValue(component); + } + + public override AttributeCollection Attributes + { + get + { + return wrappedPropertyDescriptor.Attributes; + } + } + + public override string Category + { + get + { + return wrappedPropertyDescriptor.Category; + } + } + + public override Type ComponentType + { + get + { + return wrappedPropertyDescriptor.ComponentType; + } + } + + public override TypeConverter Converter + { + get + { + return wrappedPropertyDescriptor.Converter; + } + } + + public override string Description + { + get + { + return wrappedPropertyDescriptor.Description; + } + } + + public override bool DesignTimeOnly + { + get + { + return wrappedPropertyDescriptor.DesignTimeOnly; + } + } + + public override string DisplayName + { + get + { + return wrappedPropertyDescriptor.DisplayName; + } + } + + public override bool IsBrowsable + { + get + { + return wrappedPropertyDescriptor.IsBrowsable; + } + } + + public override bool IsLocalizable + { + get + { + return wrappedPropertyDescriptor.IsLocalizable; + } + } + + public override string Name + { + get + { + return wrappedPropertyDescriptor.Name; + } + } + + public override Type PropertyType + { + get + { + return wrappedPropertyDescriptor.PropertyType; + } + } + + public override bool SupportsChangeEvents + { + get + { + return wrappedPropertyDescriptor.SupportsChangeEvents; + } + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Resources/Busy indicator.gif =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/Copy.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/CopyHS.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/DeleteHS.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/Paste.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/PasteLarge.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/PropertiesHS.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/Riskeer.ico =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/SplashScreenBackground.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/application_import_blue.ico =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/application_import_blue.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/application_view_list.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/arrow-000-medium-question-mark.ico =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/arrow-000-medium.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/arrow-stop-090.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/arrow-stop-270.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/arrow.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/brick.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/broom.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/bug-exclamation.ico =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/error.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/exclamation.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/folder.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/icon_clear_all_messages.PNG =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/information.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/key.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/project-16.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/project_explorer.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/properties_panel.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/table-export.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/table-import.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/table_refresh.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/textfield_rename.png =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Resources/warning.ico =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/SaveProjectActivity.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/SaveProjectActivity.cs (revision 0) +++ Core/Gui/src/Core.Gui/SaveProjectActivity.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,181 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Globalization; +using System.IO; +using Core.Common.Base.Data; +using Core.Common.Base.Service; +using Core.Common.Base.Storage; +using Core.Gui.Properties; +using log4net; +using CoreCommonBaseResources = Core.Common.Base.Properties.Resources; + +namespace Core.Gui +{ + /// + /// Activity to save an . + /// + public class SaveProjectActivity : Activity + { + private readonly ILog log = LogManager.GetLogger(typeof(SaveProjectActivity)); + private readonly bool savingExistingProject; + private readonly IProject project; + private readonly string filePath; + private readonly IStoreProject storeProject; + private readonly IProjectOwner projectOwner; + private int totalNumberOfSteps; + + private bool cancel; + + /// + /// Creates a new instance of . + /// + /// The project to be saved. + /// The location to save the project to. + /// When true it indicates that + /// is already located at . When false then + /// is not already located at . + /// The object responsible for saving . + /// The object responsible for hosting . + /// Thrown when any input argument is null. + public SaveProjectActivity(IProject project, string filePath, bool savingExistingProject, IStoreProject storeProject, IProjectOwner projectOwner) + { + if (project == null) + { + throw new ArgumentNullException(nameof(project)); + } + + if (filePath == null) + { + throw new ArgumentNullException(nameof(filePath)); + } + + if (storeProject == null) + { + throw new ArgumentNullException(nameof(storeProject)); + } + + if (projectOwner == null) + { + throw new ArgumentNullException(nameof(projectOwner)); + } + + this.savingExistingProject = savingExistingProject; + this.project = project; + this.filePath = filePath; + this.storeProject = storeProject; + this.projectOwner = projectOwner; + + Description = savingExistingProject + ? Resources.SaveProjectActivity_Save_existing_project + : Resources.SaveProjectActivity_Save_project; + } + + protected override void OnRun() + { + cancel = false; + totalNumberOfSteps = savingExistingProject ? 1 : 2; + var currentStep = 1; + + if (!storeProject.HasStagedProject) + { + totalNumberOfSteps++; + UpdateProgressText(Resources.SaveProjectActivity_ProgressTextStepName_StagingProject, + currentStep++, + totalNumberOfSteps); + + storeProject.StageProject(project); + } + + if (cancel) + { + return; + } + + SaveProjectUncancellable(currentStep); + } + + protected override void OnCancel() + { + cancel = true; + } + + protected override void OnFinish() + { + if (State == ActivityState.Executed && !savingExistingProject) + { + InitializeProjectForNewLocation(); + } + } + + private void SaveProjectUncancellable(int currentStep) + { + try + { + UpdateProgressText(Resources.SaveProjectActivity_ProgressTextStepName_SavingProject, + currentStep, + totalNumberOfSteps); + + storeProject.SaveProjectAs(filePath); + } + catch (StorageException e) + { + log.Error(e.Message, e.InnerException); + State = ActivityState.Failed; + return; + } + catch (ArgumentException e) + { + log.Error(e.Message, e); + State = ActivityState.Failed; + return; + } + + // Override State (might be Cancelled) due to cancelling not possible + State = ActivityState.Executed; + } + + private void InitializeProjectForNewLocation() + { + UpdateProgressText(Resources.SaveProjectActivity_ProgressTextStepName_InitializeSavedProject, + totalNumberOfSteps, + totalNumberOfSteps); + + projectOwner.SetProject(project, filePath); + project.Name = Path.GetFileNameWithoutExtension(filePath); + project.NotifyObservers(); + } + + /// + /// Updates the progress text. + /// + /// A short description of the current step. + /// The number of the current step. + /// The total numbers of steps. + private void UpdateProgressText(string currentStepName, int currentStep, int totalSteps) + { + ProgressText = string.Format(CultureInfo.CurrentCulture, + CoreCommonBaseResources.Activity_UpdateProgressText_CurrentStepNumber_0_of_TotalStepsNumber_1_StepDescription_2_, + currentStep, totalSteps, currentStepName); + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Selection/IApplicationSelection.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Selection/IApplicationSelection.cs (revision 0) +++ Core/Gui/src/Core.Gui/Selection/IApplicationSelection.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,34 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Selection +{ + /// + /// Interface for keeping and notifying changes to the application selection. + /// + public interface IApplicationSelection + { + /// + /// Gets or sets current selected object(s) within the application. + /// + object Selection { get; set; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Settings/GuiCoreSettings.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Settings/GuiCoreSettings.cs (revision 0) +++ Core/Gui/src/Core.Gui/Settings/GuiCoreSettings.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,49 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Settings +{ + /// + /// Container for settings in the graphical user interface. + /// + public class GuiCoreSettings + { + /// + /// Gets or sets the support email address to show in the graphical user interface. + /// + public string SupportEmailAddress { get; set; } + + /// + /// Gets or sets the support phone number to show in the graphical user interface. + /// + public string SupportPhoneNumber { get; set; } + + /// + /// Gets or sets the title to show in the main window of the graphical user interface. + /// + public string MainWindowTitle { get; set; } + + /// + /// Gets or sets the path of the manual file to use in the graphical interface. + /// + public string ManualFilePath { get; set; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Settings/ISettingsOwner.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/Settings/ISettingsOwner.cs (revision 0) +++ Core/Gui/src/Core.Gui/Settings/ISettingsOwner.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,34 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace Core.Gui.Settings +{ + /// + /// Interface declaring the members of the object that holds settings. + /// + public interface ISettingsOwner + { + /// + /// Gets the fixed settings of the user interface. + /// + GuiCoreSettings FixedSettings { get; } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/Style/DeltaresButtonStyle.xaml =================================================================== diff -u --- Core/Gui/src/Core.Gui/Style/DeltaresButtonStyle.xaml (revision 0) +++ Core/Gui/src/Core.Gui/Style/DeltaresButtonStyle.xaml (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Style/DeltaresGeneralStyle.xaml =================================================================== diff -u --- Core/Gui/src/Core.Gui/Style/DeltaresGeneralStyle.xaml (revision 0) +++ Core/Gui/src/Core.Gui/Style/DeltaresGeneralStyle.xaml (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,84 @@ + + + + + + + #008BBF + #006F99 + #9F9E8E + #C6C6C6 + #FFFFFF + #000000 + #F1F1EE + #00FFFFFF + #e4e4df + #d2d2ca + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Style/DeltaresStyle.xaml =================================================================== diff -u --- Core/Gui/src/Core.Gui/Style/DeltaresStyle.xaml (revision 0) +++ Core/Gui/src/Core.Gui/Style/DeltaresStyle.xaml (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,28 @@ + + + + + + + \ No newline at end of file Index: Core/Gui/src/Core.Gui/Style/Symbols/Deltares-Riskeer-Symbols.ttf =================================================================== diff -u Binary files differ Index: Core/Gui/src/Core.Gui/Style/Symbols/RiskeerSymbols.xaml =================================================================== diff -u --- Core/Gui/src/Core.Gui/Style/Symbols/RiskeerSymbols.xaml (revision 0) +++ Core/Gui/src/Core.Gui/Style/Symbols/RiskeerSymbols.xaml (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,4 @@ + + pack://application:,,,/Core.Gui;component/Style/Symbols/#Deltares-Riskeer-Symbols + \ No newline at end of file Index: Core/Gui/src/Core.Gui/UITypeEditors/ColorEditor.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/UITypeEditors/ColorEditor.cs (revision 0) +++ Core/Gui/src/Core.Gui/UITypeEditors/ColorEditor.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,77 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Drawing; +using System.Drawing.Design; +using System.Windows.Forms; + +namespace Core.Gui.UITypeEditors +{ + /// + /// This class defines dialog from which the user can select a color. + /// + public class ColorEditor : UITypeEditor + { + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.Modal; + } + + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + if (value is Color) + { + var color = (Color) value; + + var colorDialog = new ColorDialog + { + Color = color, + AllowFullOpen = true, + FullOpen = true + }; + + if (colorDialog.ShowDialog() == DialogResult.OK) + { + value = colorDialog.Color; + } + } + + return value; + } + + public override bool GetPaintValueSupported(ITypeDescriptorContext context) + { + return true; + } + + public override void PaintValue(PaintValueEventArgs e) + { + var color = (Color) e.Value; + + using (var brush = new SolidBrush(color)) + { + e.Graphics.FillRectangle(brush, e.Bounds); + } + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/UITypeEditors/SelectionEditor.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/UITypeEditors/SelectionEditor.cs (revision 0) +++ Core/Gui/src/Core.Gui/UITypeEditors/SelectionEditor.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,155 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.Drawing.Design; +using System.Linq; +using System.Windows.Forms; +using System.Windows.Forms.Design; +using Core.Gui.PropertyBag; + +namespace Core.Gui.UITypeEditors +{ + /// + /// This class provides a base implementation of and defines a drop down list + /// edit-control used for calculation input data. + /// + /// The type of items that populate the list-edit control. + /// The type which' properties populates the dropdown editor. + public class SelectionEditor : UITypeEditor + where TProperty : class + where TPropertiesClass : IObjectProperties + { + private IWindowsFormsEditorService editorService; + + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.DropDown; + } + + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + if (provider != null) + { + editorService = (IWindowsFormsEditorService) provider.GetService(typeof(IWindowsFormsEditorService)); + } + + if (editorService != null && context != null) + { + // Create editor: + using (ListBox listBox = CreateSelectionControl(context)) + { + // Open editor for user to select an item: + editorService.DropDownControl(listBox); + + // Return user selected object, or original value if user did not select anything: + if (listBox.SelectedItem == null) + { + return value; + } + + if (ReferenceEquals(listBox.SelectedItem, NullItem)) + { + return null; + } + + return listBox.SelectedItem; + } + } + + return base.EditValue(context, provider, value); + } + + /// + /// Sets which member to show of in the dropdown editor. + /// + protected string DisplayMember { private get; set; } + + /// + /// Gets or sets the item to show which represents a null value. + /// + protected TProperty NullItem { get; set; } + + /// + /// Gets the available options which populate the dropdown editor. + /// + /// The context on which to base the available options. + /// A of objects of type which contains all the available options. + protected virtual IEnumerable GetAvailableOptions(ITypeDescriptorContext context) + { + return Enumerable.Empty(); + } + + /// + /// Gets the current option which should be selected in the dropdown editor. + /// + /// The context on which to base the current option. + /// The object of type which is currently selected. + protected virtual TProperty GetCurrentOption(ITypeDescriptorContext context) + { + return null; + } + + /// + /// Takes a context and from this, obtains the object which populates the dropdown editor. + /// + /// The context from which the object is obtained. + /// The object which' properties populates the dropdown editor. + protected static TPropertiesClass GetPropertiesObject(ITypeDescriptorContext context) + { + return (TPropertiesClass) ((DynamicPropertyBag) context.Instance).WrappedObject; + } + + private ListBox CreateSelectionControl(ITypeDescriptorContext context) + { + var listBox = new ListBox + { + SelectionMode = SelectionMode.One, + DisplayMember = DisplayMember + }; + listBox.SelectedValueChanged += (sender, eventArgs) => editorService.CloseDropDown(); + + if (NullItem != null) + { + int index = listBox.Items.Add(NullItem); + if (GetCurrentOption(context) == null) + { + listBox.SelectedIndex = index; + } + } + + listBox.BeginUpdate(); + foreach (TProperty option in GetAvailableOptions(context)) + { + int index = listBox.Items.Add(option); + if (Equals(GetCurrentOption(context), option)) + { + listBox.SelectedIndex = index; + } + } + + listBox.EndUpdate(); + return listBox; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/ViewPropertyEditor.cs =================================================================== diff -u --- Core/Gui/src/Core.Gui/ViewPropertyEditor.cs (revision 0) +++ Core/Gui/src/Core.Gui/ViewPropertyEditor.cs (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -0,0 +1,72 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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.ComponentModel; +using System.Drawing.Design; +using Core.Gui.Commands; +using Core.Gui.PropertyBag; + +namespace Core.Gui +{ + /// + /// + /// Use this type in combination with on properties in + /// property classes which you want to edit with a view. + /// + /// + /// The property grid will display an ellipsis button (...). Clicking on the button + /// will open the default view for the data object in the central tabbed document area + /// of the application. The view will remain open (is not modal) until closed by the user. + /// + /// + /// + /// Usage (for example): + /// + /// [Editor(typeof(ViewPropertyEditor), typeof(UITypeEditor))] + /// public Foo SomeFooProperty + /// { + /// get { return data.Foo; } + /// set { data.Foo = value; } + /// } + /// + /// This would open a view registered for the Foo datatype. + /// + public class ViewPropertyEditor : UITypeEditor + { + /// + /// Gets or sets the view commands. + /// + /// Value should be injected before can be accessed by user. + public static IViewCommands ViewCommands { get; set; } + + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.Modal; + } + + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + ViewCommands.OpenView(value); + return value; + } + } +} \ No newline at end of file Index: Core/Gui/src/Core.Gui/nl/Xceed.Wpf.AvalonDock.resources.dll =================================================================== diff -u Binary files differ Index: Riskeer.sln =================================================================== diff -u -r4b9e28a28b8004dc9dfca896c32e2a21c10a2405 -r434415295de74c310ce6d3cdd0100c28838cf9ea --- Riskeer.sln (.../Riskeer.sln) (revision 4b9e28a28b8004dc9dfca896c32e2a21c10a2405) +++ Riskeer.sln (.../Riskeer.sln) (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) @@ -125,11 +125,6 @@ {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Common.Gui", "Core\Common\src\Core.Common.Gui\Core.Common.Gui.csproj", "{30E4C2AE-719E-4D70-9FA9-668A9767FBFA}" - ProjectSection(ProjectDependencies) = postProject - {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Common.Base", "Core\Common\src\Core.Common.Base\Core.Common.Base.csproj", "{3BBFD65B-B277-4E50-AE6D-BD24C3434609}" ProjectSection(ProjectDependencies) = postProject {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} @@ -1767,6 +1762,17 @@ {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gui", "Gui", "{94E919CC-F375-485D-A849-3CE3FCC9B2C3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8BE49C65-DD09-4890-82B1-5216BF13E757}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F73AF5D7-DDD9-4A48-A171-037817B59056}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Gui", "Core\Gui\src\Core.Gui\Core.Gui.csproj", "{FE63A65E-C5AF-456D-A786-912F9B7E26A1}" + ProjectSection(ProjectDependencies) = postProject + {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -1792,12 +1798,6 @@ {F49BD8B2-332A-4C91-A196-8CCE0A2C7D98}.Release|x86.Build.0 = Release|x86 {F49BD8B2-332A-4C91-A196-8CCE0A2C7D98}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 {F49BD8B2-332A-4C91-A196-8CCE0A2C7D98}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 - {30E4C2AE-719E-4D70-9FA9-668A9767FBFA}.Debug|x86.ActiveCfg = Debug|x86 - {30E4C2AE-719E-4D70-9FA9-668A9767FBFA}.Debug|x86.Build.0 = Debug|x86 - {30E4C2AE-719E-4D70-9FA9-668A9767FBFA}.Release|x86.ActiveCfg = Release|x86 - {30E4C2AE-719E-4D70-9FA9-668A9767FBFA}.Release|x86.Build.0 = Release|x86 - {30E4C2AE-719E-4D70-9FA9-668A9767FBFA}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 - {30E4C2AE-719E-4D70-9FA9-668A9767FBFA}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 {3BBFD65B-B277-4E50-AE6D-BD24C3434609}.Debug|x86.ActiveCfg = Debug|x86 {3BBFD65B-B277-4E50-AE6D-BD24C3434609}.Debug|x86.Build.0 = Debug|x86 {3BBFD65B-B277-4E50-AE6D-BD24C3434609}.Release|x86.ActiveCfg = Release|x86 @@ -3595,6 +3595,12 @@ {79656871-341E-42F7-AEB0-98E517E55312}.Release|x86.Build.0 = Release|x86 {79656871-341E-42F7-AEB0-98E517E55312}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 {79656871-341E-42F7-AEB0-98E517E55312}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 + {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.Debug|x86.ActiveCfg = Debug|x86 + {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.Debug|x86.Build.0 = Debug|x86 + {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.Release|x86.ActiveCfg = Release|x86 + {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.Release|x86.Build.0 = Release|x86 + {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 + {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3606,7 +3612,6 @@ {C90B77DA-E421-43CC-B82E-529651BC21AC} = {8261CCE1-98D7-465B-BC94-4ED239DE7F2E} {8261CCE1-98D7-465B-BC94-4ED239DE7F2E} = {9E35F3EA-D3C3-4D80-8399-689C49B68324} {F49BD8B2-332A-4C91-A196-8CCE0A2C7D98} = {8261CCE1-98D7-465B-BC94-4ED239DE7F2E} - {30E4C2AE-719E-4D70-9FA9-668A9767FBFA} = {8261CCE1-98D7-465B-BC94-4ED239DE7F2E} {3BBFD65B-B277-4E50-AE6D-BD24C3434609} = {8261CCE1-98D7-465B-BC94-4ED239DE7F2E} {9A2D67E6-26AC-4D17-B11A-2B4372F2F572} = {8261CCE1-98D7-465B-BC94-4ED239DE7F2E} {0D9858E1-CF2D-4DE5-AC0E-64401900D531} = {9E35F3EA-D3C3-4D80-8399-689C49B68324} @@ -3976,6 +3981,10 @@ {7FB79768-1A8B-41CA-9614-8EC6C3C79482} = {435F0AB1-1180-47D3-9BCB-3B5FF365236C} {95147D8E-A2E2-438F-A329-37A093D6E0AA} = {3ED34ACD-41C9-4251-81EC-7493E0BFF57D} {79656871-341E-42F7-AEB0-98E517E55312} = {1F0D20C2-7F04-431D-AF22-95A31FD53733} + {94E919CC-F375-485D-A849-3CE3FCC9B2C3} = {89F6BC2C-78E6-42F1-A056-704C877B5453} + {8BE49C65-DD09-4890-82B1-5216BF13E757} = {94E919CC-F375-485D-A849-3CE3FCC9B2C3} + {F73AF5D7-DDD9-4A48-A171-037817B59056} = {94E919CC-F375-485D-A849-3CE3FCC9B2C3} + {FE63A65E-C5AF-456D-A786-912F9B7E26A1} = {8BE49C65-DD09-4890-82B1-5216BF13E757} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {039D31AA-B517-4354-B8CD-0B2B826D0B1F}