Index: src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeViewController.cs =================================================================== diff -u -r5fc71a385897af92ccb092f2f969b5709afab85a -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeViewController.cs (.../TreeViewController.cs) (revision 5fc71a385897af92ccb092f2f969b5709afab85a) +++ src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeViewController.cs (.../TreeViewController.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -174,63 +174,72 @@ /// the object bound to this node public void UpdateNode(ITreeNode treeNode, object tag) { - var suspend = false; // suspend tree view locally - - if (!treeView.IsUpdateSuspended) + var treeViewControl = treeView as Control; + if (treeViewControl != null && treeViewControl.InvokeRequired) { - treeView.BeginUpdate(); - suspend = true; + UpdateNodeInvokeDelegate updateNode = UpdateNode; + treeViewControl.Invoke(updateNode, treeNode, tag); } - try + else { - var nodePresenter = treeNode.Presenter; + var suspend = false; // suspend tree view locally - if (nodePresenter == null) + if (!treeView.IsUpdateSuspended) { - Log.Debug("Can't find node presenter for tree view, object:" + tag); - return; + treeView.BeginUpdate(); + suspend = true; } - - bool wasLoaded = treeNode.IsLoaded; - if (!ReferenceEquals(treeNode.Tag, tag)) + try { - treeNode.Tag = tag; - treeNode.Presenter = ResolveNodePresenterForData(tag); - nodePresenter = treeNode.Presenter; - } + var nodePresenter = treeNode.Presenter; - nodePresenter.UpdateNode(treeNode.Parent, treeNode, treeNode.Tag); + if (nodePresenter == null) + { + Log.Debug("Can't find node presenter for tree view, object:" + tag); + return; + } - var childNodeObjects = GetChildNodeObjects(treeNode).ToArray(); - var count = childNodeObjects.Length; + bool wasLoaded = treeNode.IsLoaded; + if (!ReferenceEquals(treeNode.Tag, tag)) + { + treeNode.Tag = tag; + treeNode.Presenter = ResolveNodePresenterForData(tag); + nodePresenter = treeNode.Presenter; + } - ((TreeNode) treeNode).HasChildren = count > 0; + nodePresenter.UpdateNode(treeNode.Parent, treeNode, treeNode.Tag); - if (!treeNode.IsLoaded && !wasLoaded) - { - return; - } + var childNodeObjects = GetChildNodeObjects(treeNode).ToArray(); + var count = childNodeObjects.Length; - if (treeNode.Nodes.Count != count) - { - RefreshChildNodes(treeNode); + ((TreeNode)treeNode).HasChildren = count > 0; + + if (!treeNode.IsLoaded && !wasLoaded) + { + return; + } + + if (treeNode.Nodes.Count != count) + { + RefreshChildNodes(treeNode); + } + else + { + //update existing nodes + for (var i = 0; i < treeNode.Nodes.Count; i++) + { + UpdateNode(treeNode.Nodes[i], childNodeObjects[i]); + } + } } - else + finally { - //update existing nodes - for (var i = 0; i < treeNode.Nodes.Count; i++) + if (suspend) { - UpdateNode(treeNode.Nodes[i], childNodeObjects[i]); + treeView.EndUpdate(); } } } - finally - { - if (suspend) - { - treeView.EndUpdate(); - } - } } /// @@ -581,5 +590,10 @@ node.Tag = nodeData; presenter.UpdateNode(parentNode, node, nodeData); } + + /// + /// Delegate required to perform asynchronous calls to . + /// + delegate void UpdateNodeInvokeDelegate(ITreeNode treeNode, object tag); } } \ No newline at end of file Index: src/Common/DelftTools.Shell.Core/DelftTools.Shell.Core.csproj =================================================================== diff -u -r341078d82fcf9051b233068ad0172940aa71cff5 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Common/DelftTools.Shell.Core/DelftTools.Shell.Core.csproj (.../DelftTools.Shell.Core.csproj) (revision 341078d82fcf9051b233068ad0172940aa71cff5) +++ src/Common/DelftTools.Shell.Core/DelftTools.Shell.Core.csproj (.../DelftTools.Shell.Core.csproj) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -94,6 +94,7 @@ + Index: src/Common/DelftTools.Shell.Core/ObservableList.cs =================================================================== diff -u --- src/Common/DelftTools.Shell.Core/ObservableList.cs (revision 0) +++ src/Common/DelftTools.Shell.Core/ObservableList.cs (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +namespace DelftTools.Shell.Core +{ + /// + /// Extends the class with implementation for . + /// + /// The type of elements in the list. + public class ObservableList : List, IObservable + { + private readonly IList observers = new List(); + + public void Attach(IObserver observer) + { + observers.Add(observer); + } + + public void Detach(IObserver observer) + { + observers.Remove(observer); + } + + public void NotifyObservers() + { + foreach (var observer in observers) + { + observer.UpdateObserver(); + } + } + } +} \ No newline at end of file Index: src/DeltaShell/DeltaShell.Gui/PropertyGridView.cs =================================================================== diff -u -rb1dd752c6ad8f3c7125d26784482cf7d10581048 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/DeltaShell/DeltaShell.Gui/PropertyGridView.cs (.../PropertyGridView.cs) (revision b1dd752c6ad8f3c7125d26784482cf7d10581048) +++ src/DeltaShell/DeltaShell.Gui/PropertyGridView.cs (.../PropertyGridView.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -86,7 +86,15 @@ public void UpdateObserver() { - Refresh(); + if (InvokeRequired) + { + ArgumentlessDelegate d = UpdateObserver; + Invoke(d, new object[0]); + } + else + { + Refresh(); + } } public object GetObjectProperties(object sourceData) @@ -236,6 +244,11 @@ return propertyBag != null ? propertyBag.GetContentType() : obj.GetType(); } + /// + /// This delegate enabled asynchronous calls to methods without arguments. + /// + delegate void ArgumentlessDelegate(); + #region IPropertyGrid Members public object Data Index: src/Plugins/Wti/Wti.Data/PipingFailureMechanism.cs =================================================================== diff -u -r7e20ab62aae77f680275d9acd08f81cd12d37b97 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Plugins/Wti/Wti.Data/PipingFailureMechanism.cs (.../PipingFailureMechanism.cs) (revision 7e20ab62aae77f680275d9acd08f81cd12d37b97) +++ src/Plugins/Wti/Wti.Data/PipingFailureMechanism.cs (.../PipingFailureMechanism.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; + using DelftTools.Shell.Core; namespace Wti.Data @@ -17,7 +18,7 @@ /// public PipingFailureMechanism() { - SurfaceLines = Enumerable.Empty(); + SurfaceLines = new ObservableList(); SoilProfiles = Enumerable.Empty(); PipingData = new PipingData(); } Index: src/Plugins/Wti/Wti.Forms/NodePresenters/PipingFailureMechanismNodePresenter.cs =================================================================== diff -u -r4959b3b9b84eec4cb80ec43c037579d9177b3d02 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Plugins/Wti/Wti.Forms/NodePresenters/PipingFailureMechanismNodePresenter.cs (.../PipingFailureMechanismNodePresenter.cs) (revision 4959b3b9b84eec4cb80ec43c037579d9177b3d02) +++ src/Plugins/Wti/Wti.Forms/NodePresenters/PipingFailureMechanismNodePresenter.cs (.../PipingFailureMechanismNodePresenter.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -1,8 +1,10 @@ using System; using System.Collections; using System.ComponentModel; + using DelftTools.Controls; using DelftTools.Utils.Collections; + using Wti.Data; using Wti.Forms.Properties; @@ -92,7 +94,7 @@ { if (nodeData is PipingFailureMechanism) { - var wtiProject = (WtiProject) parentNodeData; + var wtiProject = (WtiProject)parentNodeData; wtiProject.ClearPipingFailureMechanism(); wtiProject.NotifyObservers(); Index: src/Plugins/Wti/Wti.Forms/NodePresenters/PipingNodePresenterBase.cs =================================================================== diff -u --- src/Plugins/Wti/Wti.Forms/NodePresenters/PipingNodePresenterBase.cs (revision 0) +++ src/Plugins/Wti/Wti.Forms/NodePresenters/PipingNodePresenterBase.cs (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -0,0 +1,223 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Linq; + +using DelftTools.Controls; +using DelftTools.Utils.Collections; + +namespace Wti.Forms.NodePresenters +{ + /// + /// Implements in a featureless way as possible, + /// to serve as a base class for all node presenters. + /// + /// The data object class corresponding with the node. + public abstract class PipingNodePresenterBase : ITreeNodePresenter + { + public ITreeView TreeView { get; set; } + + public Type NodeTagType + { + get + { + return typeof(T); + } + } + + public void UpdateNode(ITreeNode parentNode, ITreeNode node, object nodeData) + { + UpdateNode(parentNode, node, (T)nodeData); + } + + public IEnumerable GetChildNodeObjects(object parentNodeData, ITreeNode node) + { + return GetChildNodeObjects((T)parentNodeData, node).Cast(); + } + + public virtual bool CanRenameNode(ITreeNode node) + { + return false; + } + + public virtual bool CanRenameNodeTo(ITreeNode node, string newName) + { + return false; + } + + public void OnNodeRenamed(object nodeData, string newName) + { + var data = (T)nodeData; + OnNodeRenamed(data, newName); + } + + public virtual void OnNodeChecked(ITreeNode node) + { + // Not a checked node + } + + public DragOperations CanDrag(object nodeData) + { + return CanDrag((T)nodeData); + } + + public DragOperations CanDrop(object item, ITreeNode sourceNode, ITreeNode targetNode, DragOperations validOperations) + { + return CanDrop((T)item, sourceNode, targetNode, validOperations); + } + + public bool CanInsert(object item, ITreeNode sourceNode, ITreeNode targetNode) + { + return CanInsert((T)item, sourceNode, targetNode); + } + + public void OnDragDrop(object item, object sourceParentNodeData, object targetParentNodeData, DragOperations operation, int position) + { + OnDragDrop((T)item, sourceParentNodeData, targetParentNodeData, operation, position); + } + + public void OnNodeSelected(object nodeData) + { + OnNodeSelected((T)nodeData); + } + + public IMenuItem GetContextMenu(ITreeNode sender, object nodeData) + { + return GetContextMenu(sender, (T)nodeData); + } + + public void OnPropertyChanged(object sender, ITreeNode node, PropertyChangedEventArgs e) + { + OnPropertyChanged((T)sender, node, e); + } + + public void OnCollectionChanged(object sender, NotifyCollectionChangingEventArgs e) + { + OnCollectionChanged((T)sender, e); + } + + public bool CanRemove(object parentNodeData, object nodeData) + { + return CanRemove(parentNodeData, (T)nodeData); + } + + public bool RemoveNodeData(object parentNodeData, object nodeData) + { + return RemoveNodeData(parentNodeData, (T)nodeData); + } + + /// + /// Typed implementation method of . + /// + /// + protected abstract void UpdateNode(ITreeNode parentNode, ITreeNode node, T nodeData); + + /// + /// Typed implementation method of . + /// + /// + protected virtual IEnumerable GetChildNodeObjects(T nodeData, ITreeNode node) + { + return Enumerable.Empty(); + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual void OnNodeRenamed(T nodeData, string newName) + { + throw new InvalidOperationException(string.Format("Cannot rename tree node of type {0}.", GetType().Name)); + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual DragOperations CanDrag(T nodeData) + { + return DragOperations.None; + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual DragOperations CanDrop(T item, ITreeNode sourceNode, ITreeNode targetNode, DragOperations validOperations) + { + return DragOperations.None; + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual bool CanInsert(T item, ITreeNode sourceNode, ITreeNode targetNode) + { + return false; + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual void OnDragDrop(T item, object sourceParentNodeData, object targetParentNodeData, DragOperations operation, int position) + { + // Do nothing + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual void OnNodeSelected(T nodeData) + { + // Do nothing + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual IMenuItem GetContextMenu(ITreeNode sender, T nodeData) + { + return null; + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual void OnPropertyChanged(T sender, ITreeNode node, PropertyChangedEventArgs e) + { + // Do nothing + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual void OnCollectionChanged(T sender, NotifyCollectionChangingEventArgs e) + { + // Do nothing + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual bool CanRemove(object parentNodeData, T nodeData) + { + return false; + } + + /// + /// Typed implementation method of . + /// + /// + protected virtual bool RemoveNodeData(object parentNodeData, T nodeData) + { + throw new InvalidOperationException(String.Format("Cannot delete node of type {0}.", GetType().Name)); + } + } +} \ No newline at end of file Index: src/Plugins/Wti/Wti.Forms/NodePresenters/PipingSurfaceLineCollectionNodePresenter.cs =================================================================== diff -u -r4959b3b9b84eec4cb80ec43c037579d9177b3d02 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Plugins/Wti/Wti.Forms/NodePresenters/PipingSurfaceLineCollectionNodePresenter.cs (.../PipingSurfaceLineCollectionNodePresenter.cs) (revision 4959b3b9b84eec4cb80ec43c037579d9177b3d02) +++ src/Plugins/Wti/Wti.Forms/NodePresenters/PipingSurfaceLineCollectionNodePresenter.cs (.../PipingSurfaceLineCollectionNodePresenter.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; +using System.Linq; using System.Windows.Forms; using DelftTools.Controls; using DelftTools.Controls.Swf; @@ -37,8 +38,9 @@ public void UpdateNode(ITreeNode parentNode, ITreeNode node, object nodeData) { + var data = (IEnumerable)nodeData; node.Text = Resources.PipingSurfaceLinesCollectionName; - node.ForegroundColor = Color.FromKnownColor(KnownColor.GrayText); + node.ForegroundColor = data.Any() ? Color.FromKnownColor(KnownColor.ControlText) : Color.FromKnownColor(KnownColor.GrayText); node.Image = Resources.FolderIcon; } Index: src/Plugins/Wti/Wti.Forms/NodePresenters/PipingSurfaceLineNodePresenter.cs =================================================================== diff -u --- src/Plugins/Wti/Wti.Forms/NodePresenters/PipingSurfaceLineNodePresenter.cs (revision 0) +++ src/Plugins/Wti/Wti.Forms/NodePresenters/PipingSurfaceLineNodePresenter.cs (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -0,0 +1,19 @@ +using DelftTools.Controls; + +using Wti.Data; +using Wti.Forms.Properties; + +namespace Wti.Forms.NodePresenters +{ + /// + /// Node presenter for data nodes in the project tree view. + /// + public class PipingSurfaceLineNodePresenter : PipingNodePresenterBase + { + protected override void UpdateNode(ITreeNode parentNode, ITreeNode node, PipingSurfaceLine nodeData) + { + node.Text = nodeData.Name; + node.Image = Resources.PipingSurfaceLineIcon; + } + } +} \ No newline at end of file Index: src/Plugins/Wti/Wti.Forms/Wti.Forms.csproj =================================================================== diff -u -ra4e086ea5fbb916dd649712efd1fe6a195efc8b3 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Plugins/Wti/Wti.Forms/Wti.Forms.csproj (.../Wti.Forms.csproj) (revision a4e086ea5fbb916dd649712efd1fe6a195efc8b3) +++ src/Plugins/Wti/Wti.Forms/Wti.Forms.csproj (.../Wti.Forms.csproj) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -55,10 +55,12 @@ Component + + Index: src/Plugins/Wti/Wti.Plugin/FileImporter/PipingSurfaceLinesCsvImporter.cs =================================================================== diff -u -rbb61ed227cf79e994b84019096e4297b2fbd4527 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Plugins/Wti/Wti.Plugin/FileImporter/PipingSurfaceLinesCsvImporter.cs (.../PipingSurfaceLinesCsvImporter.cs) (revision bb61ed227cf79e994b84019096e4297b2fbd4527) +++ src/Plugins/Wti/Wti.Plugin/FileImporter/PipingSurfaceLinesCsvImporter.cs (.../PipingSurfaceLinesCsvImporter.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -5,6 +5,7 @@ using DelftTools.Shell.Core; using Wti.Data; +using Wti.IO; using WtiFormsResources = Wti.Forms.Properties.Resources; using ApplicationResources = Wti.Plugin.Properties.Resources; @@ -89,17 +90,29 @@ public object ImportItem(string path, object target = null) { - // TODO: Open file at 'path' with PipingSurfaceLinesCsvReader - // TODO: Determine line count (for progress) - // TODO: For each line... - // TODO: Check ShouldCancel for early abort - // TODO: Read line - // TODO: Parse line - // TODO: Create PipingSurfaceLine - // TODO: Set data on PipingSurfaceLine - // TODO: Add all PipingSurfaceLines to 'target' if no errors occur. + List readSurfaceLines; + using (var reader = new PipingSurfaceLinesCsvReader(path)) + { + var itemCount = reader.GetSurfaceLinesCount(); + readSurfaceLines = new List(itemCount); + for (int i = 0; i < itemCount; i++) + { + // TODO: Check ShouldCancel for early abort + readSurfaceLines.Add(reader.ReadLine()); + } + } + + var targetCollection = (ICollection)target; + foreach (var readSurfaceLine in readSurfaceLines) + { + targetCollection.Add(readSurfaceLine); + } - // TODO: Notifying observer? + var observableTarget = targetCollection as IObservable; + if (observableTarget != null) + { + observableTarget.NotifyObservers(); + } return target; } Index: src/Plugins/Wti/Wti.Plugin/WtiGuiPlugin.cs =================================================================== diff -u -r85de34918096850be7844fe93a73336cd7c29d3e -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- src/Plugins/Wti/Wti.Plugin/WtiGuiPlugin.cs (.../WtiGuiPlugin.cs) (revision 85de34918096850be7844fe93a73336cd7c29d3e) +++ src/Plugins/Wti/Wti.Plugin/WtiGuiPlugin.cs (.../WtiGuiPlugin.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -78,6 +78,7 @@ { ImportSurfaceLinesAction = Gui.CommandHandler.ImportToGuiSelection }; + yield return new PipingSurfaceLineNodePresenter(); yield return new PipingSoilProfileCollectionNodePresenter { ImportSoilProfilesAction = Gui.CommandHandler.ImportToGuiSelection Index: test/Common/DelftTools.Tests/DelftTools.Tests.csproj =================================================================== diff -u -r910cccc26d73c3fe1828c6f1f10e44fbe8fa130a -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Common/DelftTools.Tests/DelftTools.Tests.csproj (.../DelftTools.Tests.csproj) (revision 910cccc26d73c3fe1828c6f1f10e44fbe8fa130a) +++ test/Common/DelftTools.Tests/DelftTools.Tests.csproj (.../DelftTools.Tests.csproj) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -133,6 +133,7 @@ + Index: test/Common/DelftTools.Tests/Shell/Core/ObservableListTest.cs =================================================================== diff -u --- test/Common/DelftTools.Tests/Shell/Core/ObservableListTest.cs (revision 0) +++ test/Common/DelftTools.Tests/Shell/Core/ObservableListTest.cs (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +using DelftTools.Shell.Core; + +using NUnit.Framework; + +using Rhino.Mocks; + +namespace DelftTools.Tests.Shell.Core +{ + [TestFixture] + public class ObservableListTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var list = new ObservableList(); + + // Assert + Assert.IsInstanceOf>(list); + Assert.IsInstanceOf(list); + } + + [Test] + public void NotifyObservers_WithObserverAttached_ObserverIsNotified() + { + // Setup + var mocks = new MockRepository(); + var observer = mocks.StrictMock(); + observer.Expect(o => o.UpdateObserver()); // Expect to be called once + mocks.ReplayAll(); + + var list = new ObservableList(); + list.Attach(observer); + + // Call + list.NotifyObservers(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void NotifyObserver_AttachedObserverDetachedAgain_ObserverNoLongerNotified() + { + // Setup + var mocks = new MockRepository(); + var observer = mocks.StrictMock(); + mocks.ReplayAll(); + + var list = new ObservableList(); + list.Attach(observer); + list.Detach(observer); + + // Call + list.NotifyObservers(); + + // Assert + mocks.VerifyAll(); // Expect no calls on 'observer' + } + } +} \ No newline at end of file Index: test/Plugins/Wti/Wti.Data.Test/PipingFailureMechanismTest.cs =================================================================== diff -u -r4959b3b9b84eec4cb80ec43c037579d9177b3d02 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.Data.Test/PipingFailureMechanismTest.cs (.../PipingFailureMechanismTest.cs) (revision 4959b3b9b84eec4cb80ec43c037579d9177b3d02) +++ test/Plugins/Wti/Wti.Data.Test/PipingFailureMechanismTest.cs (.../PipingFailureMechanismTest.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -23,6 +23,7 @@ // assert CollectionAssert.IsEmpty(piping.SurfaceLines); + Assert.IsInstanceOf>(piping.SurfaceLines); CollectionAssert.IsEmpty(piping.SoilProfiles); Assert.IsNotNull(piping.PipingData); } Index: test/Plugins/Wti/Wti.Data.Test/PipingSurfaceLineTest.cs =================================================================== diff -u -rc42d0c47753135357002db6026ebbefc3603a62b -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.Data.Test/PipingSurfaceLineTest.cs (.../PipingSurfaceLineTest.cs) (revision c42d0c47753135357002db6026ebbefc3603a62b) +++ test/Plugins/Wti/Wti.Data.Test/PipingSurfaceLineTest.cs (.../PipingSurfaceLineTest.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -44,7 +44,13 @@ // Setup var surfaceLine = new PipingSurfaceLine(); - var sourceData = new[]{new Point3D{X=1.1,Y=2.2,Z=3.3}}; + var sourceData = new[] + { + new Point3D + { + X = 1.1, Y = 2.2, Z = 3.3 + } + }; // Call surfaceLine.SetGeometry(sourceData); Index: test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingNodePresenterBaseTest.cs =================================================================== diff -u --- test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingNodePresenterBaseTest.cs (revision 0) +++ test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingNodePresenterBaseTest.cs (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -0,0 +1,334 @@ +using System; +using System.ComponentModel; +using System.Linq; + +using DelftTools.Controls; +using DelftTools.Utils.Collections; + +using NUnit.Framework; + +using Rhino.Mocks; + +using Wti.Forms.NodePresenters; + +namespace Wti.Forms.Test.NodePresenters +{ + [TestFixture] + public class PipingNodePresenterBaseTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Assert + Assert.AreEqual(typeof(double), nodePresenter.NodeTagType); + Assert.IsNull(nodePresenter.TreeView); + } + + [Test] + public void UpdateNode_WithData_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var parentNode = mocks.StrictMock(); + var pipingNode = mocks.StrictMock(); + var pipingData = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + nodePresenter.UpdateNode(parentNode, pipingNode, pipingData); + + // Assert + mocks.VerifyAll(); // Expect no calls on mocks + } + + [Test] + public void GetChildNodeObjects_Always_ReturnNoChildData() + { + // Setup + var mocks = new MockRepository(); + var nodeMock = mocks.StrictMock(); + var dataMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + var children = nodePresenter.GetChildNodeObjects(dataMock, nodeMock).OfType().ToArray(); + + // Assert + CollectionAssert.IsEmpty(children); + mocks.VerifyAll(); // Expect no calls on tree node + } + + [Test] + public void CanRenameNode_Always_ReturnFalse() + { + // Setup + var mocks = new MockRepository(); + var nodeMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + var renameAllowed = nodePresenter.CanRenameNode(nodeMock); + + // Assert + Assert.IsFalse(renameAllowed); + mocks.VerifyAll(); // Expect no calls on tree node + } + + [Test] + public void CanRenameNodeTo_Always_ReturnFalse() + { + // Setup + var mocks = new MockRepository(); + var nodeMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + var renameAllowed = nodePresenter.CanRenameNodeTo(nodeMock, ""); + + // Assert + Assert.IsFalse(renameAllowed); + mocks.ReplayAll(); // Expect no calls on tree node + } + + [Test] + public void OnNodeRenamed_Always_ThrowInvalidOperationException() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + TestDelegate call = () => { nodePresenter.OnNodeRenamed(dataMock, ""); }; + + // Assert + var exception = Assert.Throws(call); + var expectedMessage = string.Format("Cannot rename tree node of type {0}.", nodePresenter.GetType().Name); + Assert.AreEqual(expectedMessage, exception.Message); + mocks.ReplayAll(); // Expect no calls on tree node + } + + [Test] + public void OnNodeChecked_Always_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var nodeMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + nodePresenter.OnNodeChecked(nodeMock); + + // Assert + mocks.VerifyAll(); // Expect no calls on tree node + } + + [Test] + public void CanDrag_Always_ReturnNone() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + DragOperations dragAllowed = nodePresenter.CanDrag(dataMock); + + // Assert + Assert.AreEqual(DragOperations.None, dragAllowed); + mocks.VerifyAll(); + } + + [Test] + public void CanDrop_Always_ReturnNone() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + var sourceMock = mocks.StrictMock(); + var targetMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + DragOperations dropAllowed = nodePresenter.CanDrop(dataMock, sourceMock, targetMock, DragOperations.Move); + + // Assert + Assert.AreEqual(DragOperations.None, dropAllowed); + mocks.VerifyAll(); // Expect no calls on mocks. + } + + [Test] + public void CanInsert_Always_ReturnFalse() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + var sourceMock = mocks.StrictMock(); + var targetMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + bool insertionAllowed = nodePresenter.CanInsert(dataMock, sourceMock, targetMock); + + // Assert + Assert.IsFalse(insertionAllowed); + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void OnDragDrop_Always_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + var sourceParentNodeMock = mocks.StrictMock(); + var targetParentNodeDataMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + nodePresenter.OnDragDrop(dataMock, sourceParentNodeMock, targetParentNodeDataMock, DragOperations.Move, 2); + + // Assert + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void OnNodeSelected_Always_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + nodePresenter.OnNodeSelected(dataMock); + + // Assert + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void GetContextMenu_Always_ReturnsNull() + { + // Setup + var mocks = new MockRepository(); + var nodeMock = mocks.StrictMock(); + var dataMock = mocks.StrictMock(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + mocks.ReplayAll(); + + // Call + var contextMenu = nodePresenter.GetContextMenu(nodeMock, dataMock); + + // Assert + Assert.IsNull(contextMenu); + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void OnPropertyChange_Always_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + var nodeMock = mocks.StrictMock(); + var eventArgsMock = mocks.StrictMock(""); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + nodePresenter.OnPropertyChanged(dataMock, nodeMock, eventArgsMock); + + // Assert + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void OnCollectionChange_Always_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + var eventArgsMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + nodePresenter.OnCollectionChanged(dataMock, eventArgsMock); + + // Assert + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void CanRemove_Always_ReturnFalse() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + bool removalAllowed = nodePresenter.CanRemove(null, dataMock); + + // Assert + Assert.IsFalse(removalAllowed); + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void RemoveNodeData_Always_ThrowInvalidOperationException() + { + // Setup + var nodePresenter = new SimplePipingNodePresenterBase(); + + // Call + TestDelegate call = () => nodePresenter.RemoveNodeData(null, new SomePipingClass()); + + // Assert + var exception = Assert.Throws(call); + Assert.AreEqual(String.Format("Cannot delete node of type {0}.", nodePresenter.GetType().Name), exception.Message); + } + + private class SimplePipingNodePresenterBase : PipingNodePresenterBase + { + protected override void UpdateNode(ITreeNode parentNode, ITreeNode node, T nodeData) + { + + } + } + + public class SomePipingClass{} + } +} \ No newline at end of file Index: test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingSurfaceLineCollectionNodePresenterTest.cs =================================================================== diff -u -rbb61ed227cf79e994b84019096e4297b2fbd4527 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingSurfaceLineCollectionNodePresenterTest.cs (.../PipingSurfaceLineCollectionNodePresenterTest.cs) (revision bb61ed227cf79e994b84019096e4297b2fbd4527) +++ test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingSurfaceLineCollectionNodePresenterTest.cs (.../PipingSurfaceLineCollectionNodePresenterTest.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Drawing; using System.Linq; +using System.Windows.Forms; using DelftTools.Controls; using DelftTools.Controls.Swf; @@ -44,6 +45,28 @@ var nodePresenter = new PipingSurfaceLineCollectionNodePresenter(); + IEnumerable surfaceLinesCollection = new[]{ new PipingSurfaceLine() }; + + // Call + nodePresenter.UpdateNode(null, surfaceLinesCollectionNodeMock, surfaceLinesCollection); + + // Assert + Assert.AreEqual(WtiFormsResources.PipingSurfaceLinesCollectionName, surfaceLinesCollectionNodeMock.Text); + Assert.AreEqual(Color.FromKnownColor(KnownColor.ControlText), surfaceLinesCollectionNodeMock.ForegroundColor); + Assert.AreEqual(16, surfaceLinesCollectionNodeMock.Image.Height); + Assert.AreEqual(16, surfaceLinesCollectionNodeMock.Image.Width); + } + + [Test] + public void UpdateNode_CollectionIsEmpty_InitializeNodeWithGreyedOutText() + { + // Setup + var mocks = new MockRepository(); + var surfaceLinesCollectionNodeMock = mocks.Stub(); + mocks.ReplayAll(); + + var nodePresenter = new PipingSurfaceLineCollectionNodePresenter(); + IEnumerable surfaceLinesCollection = Enumerable.Empty(); // Call Index: test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingSurfaceLineNodePresenterTest.cs =================================================================== diff -u --- test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingSurfaceLineNodePresenterTest.cs (revision 0) +++ test/Plugins/Wti/Wti.Forms.Test/NodePresenters/PipingSurfaceLineNodePresenterTest.cs (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -0,0 +1,49 @@ +using DelftTools.Controls; + +using NUnit.Framework; + +using Rhino.Mocks; + +using Wti.Data; +using Wti.Forms.NodePresenters; + +namespace Wti.Forms.Test.NodePresenters +{ + [TestFixture] + public class PipingSurfaceLineNodePresenterTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var nodePresenter = new PipingSurfaceLineNodePresenter(); + + // Assert + Assert.IsInstanceOf>(nodePresenter); + } + + [Test] + public void UpdateNode_NodeWithData_InitializeNode() + { + // Setup + var mocks = new MockRepository(); + var parentNodeMock = mocks.StrictMock(); + var dataNodeMock = mocks.Stub(); + mocks.ReplayAll(); + + const string name = ""; + var surfaceLine = new PipingSurfaceLine { Name = name }; + + var nodePresenter = new PipingSurfaceLineNodePresenter(); + + // Call + nodePresenter.UpdateNode(parentNodeMock, dataNodeMock, surfaceLine); + + // Assert + Assert.AreEqual(name, dataNodeMock.Text); + Assert.AreEqual(16, dataNodeMock.Image.Height); + Assert.AreEqual(16, dataNodeMock.Image.Width); + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: test/Plugins/Wti/Wti.Forms.Test/Wti.Forms.Test.csproj =================================================================== diff -u -r4959b3b9b84eec4cb80ec43c037579d9177b3d02 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.Forms.Test/Wti.Forms.Test.csproj (.../Wti.Forms.Test.csproj) (revision 4959b3b9b84eec4cb80ec43c037579d9177b3d02) +++ test/Plugins/Wti/Wti.Forms.Test/Wti.Forms.Test.csproj (.../Wti.Forms.Test.csproj) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -15,7 +15,7 @@ true bin\Debug\ - 4 + 4 DEBUG;TRACE full x86 @@ -24,7 +24,7 @@ bin\Release\ - 4 + 4 TRACE true pdbonly @@ -50,8 +50,10 @@ + + Index: test/Plugins/Wti/Wti.IO.Test/PipingSurfaceLinesCsvReaderTest.cs =================================================================== diff -u -rc42d0c47753135357002db6026ebbefc3603a62b -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.IO.Test/PipingSurfaceLinesCsvReaderTest.cs (.../PipingSurfaceLinesCsvReaderTest.cs) (revision c42d0c47753135357002db6026ebbefc3603a62b) +++ test/Plugins/Wti/Wti.IO.Test/PipingSurfaceLinesCsvReaderTest.cs (.../PipingSurfaceLinesCsvReaderTest.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -87,11 +87,39 @@ DoReadLine_OpenedValidFileWithHeaderAndTwoSurfaceLines_ReturnCreatedSurfaceLine(); } + [Test] + public void ReadLine_OpenedValidFileWithoutHeaderAndTwoSurfaceLinesWhileAtTheEndOfFile_ReturnNull() + { + // Setup + string path = Path.Combine(testDataPath, "TwoValidSurfaceLines.csv"); + + using (var reader = new PipingSurfaceLinesCsvReader(path)) + { + int surfaceLinesCount = reader.GetSurfaceLinesCount(); + for (int i = 0; i < surfaceLinesCount; i++) + { + var pipingSurfaceLine = reader.ReadLine(); + Assert.IsNotInstanceOf(pipingSurfaceLine, + "Fail Fast: Disposal logic required to be implemented in test."); + Assert.IsNotNull(pipingSurfaceLine); + } + + // Call + var result = reader.ReadLine(); + + // Assert + Assert.IsNull(result); + } + } + private void DoReadLine_OpenedValidFileWithHeaderAndTwoSurfaceLines_ReturnCreatedSurfaceLine() { // Setup string path = Path.Combine(testDataPath, "TwoValidSurfaceLines.csv"); + // Precondition: + Assert.IsTrue(File.Exists(path)); + using (var reader = new PipingSurfaceLinesCsvReader(path)) { // Call @@ -131,30 +159,5 @@ #endregion } } - - [Test] - public void ReadLine_OpenedValidFileWithoutHeaderAndTwoSurfaceLinesWhileAtTheEndOfFile_ReturnNull() - { - // Setup - string path = Path.Combine(testDataPath, "TwoValidSurfaceLines.csv"); - - using (var reader = new PipingSurfaceLinesCsvReader(path)) - { - int surfaceLinesCount = reader.GetSurfaceLinesCount(); - for (int i = 0; i < surfaceLinesCount; i++) - { - var pipingSurfaceLine = reader.ReadLine(); - Assert.IsNotInstanceOf(pipingSurfaceLine, - "Fail Fast: Disposal logic required to be implemented in test."); - Assert.IsNotNull(pipingSurfaceLine); - } - - // Call - var result = reader.ReadLine(); - - // Assert - Assert.IsNull(result); - } - } } } \ No newline at end of file Index: test/Plugins/Wti/Wti.Plugin.Test/FileImporter/PipingSurfaceLineCsvImporterTest.cs =================================================================== diff -u -rbb61ed227cf79e994b84019096e4297b2fbd4527 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.Plugin.Test/FileImporter/PipingSurfaceLineCsvImporterTest.cs (.../PipingSurfaceLineCsvImporterTest.cs) (revision bb61ed227cf79e994b84019096e4297b2fbd4527) +++ test/Plugins/Wti/Wti.Plugin.Test/FileImporter/PipingSurfaceLineCsvImporterTest.cs (.../PipingSurfaceLineCsvImporterTest.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using DelftTools.Shell.Core; +using DelftTools.TestUtils; using NUnit.Framework; @@ -17,6 +20,8 @@ [TestFixture] public class PipingSurfaceLineCsvImporterTest { + private readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Plugins.Wti.WtiIOPath, "PipingSurfaceLinesCsvReader"); + [Test] public void DefaultConstructor_ExpectedValues() { @@ -80,21 +85,43 @@ public void ImportItem_ImportingToValidTargetWithValidFile_ImportSurfaceLinesToCollection() { // Setup - const string validFilePath = ""; - var piping = new PipingFailureMechanism(); + string validFilePath = Path.Combine(testDataPath, "TwoValidSurfaceLines.csv"); - var importer = new PipingSurfaceLinesCsvImporter(); + var mocks = new MockRepository(); + var observer = mocks.StrictMock(); + observer.Expect(o => o.UpdateObserver()); + mocks.ReplayAll(); - var importTarget = piping.SurfaceLines; + var observableSurfaceLinesList = new ObservableList(); + observableSurfaceLinesList.Attach(observer); + var importer = new PipingSurfaceLinesCsvImporter(); + // Precondition - Assert.IsTrue(importer.CanImportOn(importTarget)); + CollectionAssert.IsEmpty(observableSurfaceLinesList); + Assert.IsTrue(importer.CanImportOn(observableSurfaceLinesList)); + Assert.IsTrue(File.Exists(validFilePath)); // Call - var importedItem = importer.ImportItem(validFilePath, importTarget); + var importedItem = importer.ImportItem(validFilePath, observableSurfaceLinesList); // Assert - Assert.AreSame(importTarget, importedItem); + Assert.AreSame(observableSurfaceLinesList, importedItem); + var importTargetArray = observableSurfaceLinesList.ToArray(); + Assert.AreEqual(2, importTargetArray.Length); + + // Sample some of the imported data: + var firstSurfaceLine = importTargetArray[0]; + Assert.AreEqual("Rotterdam1", firstSurfaceLine.Name); + Assert.AreEqual(8, firstSurfaceLine.Points.Count()); + Assert.AreEqual(427776.654093, firstSurfaceLine.StartingWorldPoint.Y); + + var secondSurfaceLine = importTargetArray[1]; + Assert.AreEqual("ArtificalLocal", secondSurfaceLine.Name); + Assert.AreEqual(3, secondSurfaceLine.Points.Count()); + Assert.AreEqual(4.4, secondSurfaceLine.EndingWorldPoint.X); + + mocks.VerifyAll(); } } } \ No newline at end of file Index: test/Plugins/Wti/Wti.Plugin.Test/Wti.Plugin.Test.csproj =================================================================== diff -u -ra4e086ea5fbb916dd649712efd1fe6a195efc8b3 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.Plugin.Test/Wti.Plugin.Test.csproj (.../Wti.Plugin.Test.csproj) (revision a4e086ea5fbb916dd649712efd1fe6a195efc8b3) +++ test/Plugins/Wti/Wti.Plugin.Test/Wti.Plugin.Test.csproj (.../Wti.Plugin.Test.csproj) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -95,6 +95,10 @@ {1d3d58b6-ef7e-401e-92a0-104067d222ee} Wti.Plugin + + {efa25023-cf6a-4ff7-8c42-b24d7f9509e1} + DelftTools.TestUtils + Index: test/Plugins/Wti/Wti.Plugin.Test/WtiGuiPluginTest.cs =================================================================== diff -u -r4959b3b9b84eec4cb80ec43c037579d9177b3d02 -rab8c3b732c3aaadc8e55be98e132bdaf41110169 --- test/Plugins/Wti/Wti.Plugin.Test/WtiGuiPluginTest.cs (.../WtiGuiPluginTest.cs) (revision 4959b3b9b84eec4cb80ec43c037579d9177b3d02) +++ test/Plugins/Wti/Wti.Plugin.Test/WtiGuiPluginTest.cs (.../WtiGuiPluginTest.cs) (revision ab8c3b732c3aaadc8e55be98e132bdaf41110169) @@ -94,9 +94,10 @@ ITreeNodePresenter[] nodePresenters = guiPlugin.GetProjectTreeViewNodePresenters().ToArray(); // assert - Assert.AreEqual(6, nodePresenters.Length); + Assert.AreEqual(7, nodePresenters.Length); Assert.IsTrue(nodePresenters.Any(np => np is WtiProjectNodePresenter)); Assert.IsTrue(nodePresenters.Any(np => np is PipingSurfaceLineCollectionNodePresenter)); + Assert.IsTrue(nodePresenters.Any(np => np is PipingSurfaceLineNodePresenter)); Assert.IsTrue(nodePresenters.Any(np => np is PipingSoilProfileCollectionNodePresenter)); Assert.IsTrue(nodePresenters.Any(np => np is PipingDataNodePresenter)); Assert.IsTrue(nodePresenters.Any(np => np is PipingFailureMechanismNodePresenter));