/// <summary> /// Expands the block list. /// * Only expand block list of arguments /// * Only expand if the list is empty. In that case, add a single default argument. /// </summary> private protected virtual void ExpandBlockList(IWriteableBlockListInner <IWriteableBrowsingBlockNodeIndex> blockListInner, WriteableOperationList operationList) { if (!blockListInner.IsEmpty) { return; } if (!NodeHelper.IsCollectionWithExpand(blockListInner.Owner.Node, blockListInner.PropertyName)) { return; } Node NewItem = NodeHelper.CreateDefaultFromType(blockListInner.InterfaceType); Pattern NewPattern = NodeHelper.CreateEmptyPattern(); Identifier NewSource = NodeHelper.CreateEmptyIdentifier(); IBlock NewBlock = NodeTreeHelperBlockList.CreateBlock(blockListInner.Owner.Node, blockListInner.PropertyName, ReplicationStatus.Normal, NewPattern, NewSource); Action <IWriteableOperation> HandlerRedo = (IWriteableOperation operation) => RedoExpandBlockList(operation); Action <IWriteableOperation> HandlerUndo = (IWriteableOperation operation) => UndoExpandBlockList(operation); WriteableExpandArgumentOperation Operation = CreateExpandArgumentOperation(blockListInner.Owner.Node, blockListInner.PropertyName, NewBlock, NewItem, HandlerRedo, HandlerUndo, isNested: false); Operation.Redo(); operationList.Add(Operation); }
private protected virtual void InsertNewBlock(IWriteableBlockListInner <IWriteableBrowsingBlockNodeIndex> blockListInner, IWriteableInsertionNewBlockNodeIndex newBlockIndex, out IWriteableBrowsingCollectionNodeIndex nodeIndex) { IBlock NewBlock = NodeTreeHelperBlockList.CreateBlock(blockListInner.Owner.Node, blockListInner.PropertyName, ReplicationStatus.Normal, newBlockIndex.PatternNode, newBlockIndex.SourceNode); Action <IWriteableOperation> HandlerRedo = (IWriteableOperation operation) => RedoInsertNewBlock(operation); Action <IWriteableOperation> HandlerUndo = (IWriteableOperation operation) => UndoInsertNewBlock(operation); IWriteableInsertBlockOperation Operation = CreateInsertBlockOperation(blockListInner.Owner.Node, blockListInner.PropertyName, newBlockIndex.BlockIndex, NewBlock, newBlockIndex.Node, HandlerRedo, HandlerUndo, isNested: false); Operation.Redo(); SetLastOperation(Operation); CheckInvariant(); nodeIndex = Operation.BrowsingIndex; }
/// <summary> /// Creates a clone of the block and assigns it in the provided parent. /// </summary> /// <param name="parentNode">The node that will contains a reference to the cloned block upon return.</param> /// <param name="blockIndex">Position where to insert the block in <paramref name="parentNode"/>.</param> public virtual void CloneBlock(Node parentNode, int blockIndex) { Pattern PatternClone = ClonePattern(); Debug.Assert(PatternClone != null); Identifier SourceClone = CloneSource(); Debug.Assert(SourceClone != null); IBlock NewBlock = NodeTreeHelperBlockList.CreateBlock(parentNode, ParentInner.PropertyName, ChildBlock.Replication, PatternClone, SourceClone); NodeTreeHelperBlockList.InsertIntoBlockList(parentNode, ParentInner.PropertyName, blockIndex, NewBlock); NodeTreeHelper.CopyDocumentation(ChildBlock, NewBlock, cloneCommentGuid: true); // Clone children recursively. CloneChildren(parentNode, NewBlock); }
/// <summary> /// Splits a block in two at the given index. /// </summary> /// <param name="inner">The inner where the block is split.</param> /// <param name="nodeIndex">Index of the last node to stay in the old block.</param> public virtual void SplitBlock(IWriteableBlockListInner inner, IWriteableBrowsingExistingBlockNodeIndex nodeIndex) { Contract.RequireNotNull(inner, out IWriteableBlockListInner Inner); Contract.RequireNotNull(nodeIndex, out IWriteableBrowsingExistingBlockNodeIndex NodeIndex); Debug.Assert(Inner.IsSplittable(NodeIndex)); IWriteableBlockState BlockState = (IWriteableBlockState)Inner.BlockStateList[NodeIndex.BlockIndex]; ReplicationStatus Replication = BlockState.ChildBlock.Replication; Pattern NewPatternNode = NodeHelper.CreateSimplePattern(BlockState.ChildBlock.ReplicationPattern.Text); Identifier NewSourceNode = NodeHelper.CreateSimpleIdentifier(BlockState.ChildBlock.SourceIdentifier.Text); IBlock NewBlock = NodeTreeHelperBlockList.CreateBlock(Inner.Owner.Node, Inner.PropertyName, Replication, NewPatternNode, NewSourceNode); Action <IWriteableOperation> HandlerRedo = (IWriteableOperation operation) => RedoSplitBlock(operation); Action <IWriteableOperation> HandlerUndo = (IWriteableOperation operation) => UndoSplitBlock(operation); WriteableSplitBlockOperation Operation = CreateSplitBlockOperation(Inner.Owner.Node, Inner.PropertyName, NodeIndex.BlockIndex, NodeIndex.Index, NewBlock, HandlerRedo, HandlerUndo, isNested: false); Operation.Redo(); SetLastOperation(Operation); CheckInvariant(); }
/// <summary> /// Removes a range of blocks from a block list and replace them with other blocks. /// </summary> /// <param name="inner">The inner for the block list from which blocks are replaced.</param> /// <param name="firstBlockIndex">Index of the first block to remove.</param> /// <param name="lastBlockIndex">Index following the last block to remove.</param> /// <param name="indexList">List of nodes in blocks to insert.</param> public virtual void ReplaceBlockRange(IWriteableBlockListInner inner, int firstBlockIndex, int lastBlockIndex, IList <IWriteableInsertionBlockNodeIndex> indexList) { Contract.RequireNotNull(inner, out IWriteableBlockListInner Inner); Debug.Assert(firstBlockIndex >= 0 && firstBlockIndex < Inner.BlockStateList.Count); Debug.Assert(lastBlockIndex >= 0 && lastBlockIndex <= Inner.BlockStateList.Count); Debug.Assert(firstBlockIndex <= lastBlockIndex); Contract.RequireNotNull(indexList, out IList <IWriteableInsertionBlockNodeIndex> IndexList); int BlockIndex = firstBlockIndex - 1; int BlockNodeIndex = 0; foreach (IWriteableInsertionBlockNodeIndex NodeIndex in IndexList) { bool IsHandled = false; if (NodeIndex is IWriteableInsertionNewBlockNodeIndex AsNewBlockNodeIndex) { BlockIndex++; BlockNodeIndex = 0; Debug.Assert(AsNewBlockNodeIndex.BlockIndex == BlockIndex); IsHandled = true; } else if (NodeIndex is IWriteableInsertionExistingBlockNodeIndex AsExistingBlockNodeIndex) { BlockNodeIndex++; Debug.Assert(AsExistingBlockNodeIndex.BlockIndex == BlockIndex); Debug.Assert(AsExistingBlockNodeIndex.Index == BlockNodeIndex); IsHandled = true; } Debug.Assert(IsHandled); } int FinalBlockIndex = BlockIndex + 1; Action <IWriteableOperation> HandlerRedoInsertNode = (IWriteableOperation operation) => RedoInsertNewNode(operation); Action <IWriteableOperation> HandlerUndoInsertNode = (IWriteableOperation operation) => UndoInsertNewNode(operation); Action <IWriteableOperation> HandlerRedoInsertBlock = (IWriteableOperation operation) => RedoInsertNewBlock(operation); Action <IWriteableOperation> HandlerUndoInsertBlock = (IWriteableOperation operation) => UndoInsertNewBlock(operation); Action <IWriteableOperation> HandlerRedoRemoveNode = (IWriteableOperation operation) => RedoRemoveNode(operation); Action <IWriteableOperation> HandlerUndoRemoveNode = (IWriteableOperation operation) => UndoRemoveNode(operation); Action <IWriteableOperation> HandlerRedoRemoveBlock = (IWriteableOperation operation) => RedoRemoveBlock(operation); Action <IWriteableOperation> HandlerUndoRemoveBlock = (IWriteableOperation operation) => UndoRemoveBlock(operation); WriteableOperationList OperationList = CreateOperationList(); // Insert first to prevent empty block lists. foreach (IWriteableInsertionBlockNodeIndex NodeIndex in IndexList) { if (NodeIndex is IWriteableInsertionNewBlockNodeIndex AsNewBlockNodeIndex) { IBlock NewBlock = NodeTreeHelperBlockList.CreateBlock(Inner.Owner.Node, Inner.PropertyName, ReplicationStatus.Normal, AsNewBlockNodeIndex.PatternNode, AsNewBlockNodeIndex.SourceNode); IWriteableInsertBlockOperation OperationInsertBlock = CreateInsertBlockOperation(Inner.Owner.Node, Inner.PropertyName, AsNewBlockNodeIndex.BlockIndex, NewBlock, AsNewBlockNodeIndex.Node, HandlerRedoInsertBlock, HandlerUndoInsertBlock, isNested: true); OperationList.Add(OperationInsertBlock); } else if (NodeIndex is IWriteableInsertionExistingBlockNodeIndex AsExistingBlockNodeIndex) { IndexToPositionAndNode(AsExistingBlockNodeIndex, out BlockIndex, out int Index, out _, out Node Node); WriteableInsertNodeOperation OperationInsertNode = CreateInsertNodeOperation(Inner.Owner.Node, Inner.PropertyName, BlockIndex, Index, Node, HandlerRedoInsertNode, HandlerUndoInsertNode, isNested: true); OperationList.Add(OperationInsertNode); } } Debug.Assert(BlockIndex + 1 == FinalBlockIndex); for (int i = FinalBlockIndex; i < FinalBlockIndex + lastBlockIndex - firstBlockIndex; i++) { IWriteableBlockState BlockState = (IWriteableBlockState)Inner.BlockStateList[i + firstBlockIndex - FinalBlockIndex]; Debug.Assert(BlockState.StateList.Count >= 1); // Remove at FinalBlockIndex since subsequent blocks are moved as the block at FinalBlockIndex is deleted. // Same for nodes inside blokcks, delete them at 0. for (int j = 1; j < BlockState.StateList.Count; j++) { WriteableRemoveNodeOperation OperationNode = CreateRemoveNodeOperation(Inner.Owner.Node, Inner.PropertyName, FinalBlockIndex, 0, HandlerRedoRemoveNode, HandlerUndoRemoveNode, isNested: true); OperationList.Add(OperationNode); } IWriteableRemoveBlockOperation OperationBlock = CreateRemoveBlockOperation(Inner.Owner.Node, Inner.PropertyName, FinalBlockIndex, HandlerRedoRemoveBlock, HandlerUndoRemoveBlock, isNested: true); OperationList.Add(OperationBlock); } if (OperationList.Count > 0) { WriteableOperationReadOnlyList OperationReadOnlyList = OperationList.ToReadOnly(); Action <IWriteableOperation> HandlerRedo = (IWriteableOperation operation) => RedoRefresh(operation); Action <IWriteableOperation> HandlerUndo = (IWriteableOperation operation) => throw new NotImplementedException(); // Undo is not possible. WriteableGenericRefreshOperation RefreshOperation = CreateGenericRefreshOperation(RootState, HandlerRedo, HandlerUndo, isNested: false); WriteableOperationGroup OperationGroup = CreateOperationGroup(OperationReadOnlyList, RefreshOperation); OperationGroup.Redo(); SetLastOperation(OperationGroup); CheckInvariant(); } }
/// <summary> /// Inserts a range of blocks in a block list. /// </summary> /// <param name="inner">The inner for the block list in which blocks are inserted.</param> /// <param name="insertedIndex">Index where to insert the first block.</param> /// <param name="indexList">List of nodes in blocks to insert.</param> public virtual void InsertBlockRange(IWriteableBlockListInner inner, int insertedIndex, IList <IWriteableInsertionBlockNodeIndex> indexList) { Contract.RequireNotNull(inner, out IWriteableBlockListInner Inner); Debug.Assert(insertedIndex >= 0 && insertedIndex <= Inner.BlockStateList.Count); Contract.RequireNotNull(indexList, out IList <IWriteableInsertionBlockNodeIndex> IndexList); int BlockIndex = insertedIndex - 1; int BlockNodeIndex = 0; foreach (IWriteableInsertionBlockNodeIndex NodeIndex in IndexList) { bool IsHandled = false; if (NodeIndex is IWriteableInsertionNewBlockNodeIndex AsNewBlockNodeIndex) { BlockIndex++; BlockNodeIndex = 0; Debug.Assert(AsNewBlockNodeIndex.BlockIndex == BlockIndex); IsHandled = true; } else if (NodeIndex is IWriteableInsertionExistingBlockNodeIndex AsExistingBlockNodeIndex) { BlockNodeIndex++; Debug.Assert(AsExistingBlockNodeIndex.BlockIndex == BlockIndex); Debug.Assert(AsExistingBlockNodeIndex.Index == BlockNodeIndex); IsHandled = true; } Debug.Assert(IsHandled); } int FinalBlockIndex = BlockIndex + 1; Action <IWriteableOperation> HandlerRedoInsertNode = (IWriteableOperation operation) => RedoInsertNewNode(operation); Action <IWriteableOperation> HandlerUndoInsertNode = (IWriteableOperation operation) => UndoInsertNewNode(operation); Action <IWriteableOperation> HandlerRedoInsertBlock = (IWriteableOperation operation) => RedoInsertNewBlock(operation); Action <IWriteableOperation> HandlerUndoInsertBlock = (IWriteableOperation operation) => UndoInsertNewBlock(operation); WriteableOperationList OperationList = CreateOperationList(); foreach (IWriteableInsertionBlockNodeIndex NodeIndex in IndexList) { if (NodeIndex is IWriteableInsertionNewBlockNodeIndex AsNewBlockNodeIndex) { IBlock NewBlock = NodeTreeHelperBlockList.CreateBlock(Inner.Owner.Node, Inner.PropertyName, ReplicationStatus.Normal, AsNewBlockNodeIndex.PatternNode, AsNewBlockNodeIndex.SourceNode); IWriteableInsertBlockOperation OperationInsertBlock = CreateInsertBlockOperation(Inner.Owner.Node, Inner.PropertyName, AsNewBlockNodeIndex.BlockIndex, NewBlock, AsNewBlockNodeIndex.Node, HandlerRedoInsertBlock, HandlerUndoInsertBlock, isNested: true); OperationList.Add(OperationInsertBlock); } else if (NodeIndex is IWriteableInsertionExistingBlockNodeIndex AsExistingBlockNodeIndex) { IndexToPositionAndNode(AsExistingBlockNodeIndex, out BlockIndex, out int Index, out _, out Node Node); WriteableInsertNodeOperation OperationInsertNode = CreateInsertNodeOperation(Inner.Owner.Node, Inner.PropertyName, BlockIndex, Index, Node, HandlerRedoInsertNode, HandlerUndoInsertNode, isNested: true); OperationList.Add(OperationInsertNode); } } Debug.Assert(BlockIndex + 1 == FinalBlockIndex); if (OperationList.Count > 0) { WriteableOperationReadOnlyList OperationReadOnlyList = OperationList.ToReadOnly(); Action <IWriteableOperation> HandlerRedo = (IWriteableOperation operation) => RedoRefresh(operation); Action <IWriteableOperation> HandlerUndo = (IWriteableOperation operation) => throw new NotImplementedException(); // Undo is not possible. WriteableGenericRefreshOperation RefreshOperation = CreateGenericRefreshOperation(RootState, HandlerRedo, HandlerUndo, isNested: false); WriteableOperationGroup OperationGroup = CreateOperationGroup(OperationReadOnlyList, RefreshOperation); OperationGroup.Redo(); SetLastOperation(OperationGroup); CheckInvariant(); } }