/// <summary> /// Connect two connections together. This is the connection on the superior block. /// </summary> /// <param name="childConnection"></param> private void ConnectInternal(Connection childConnection) { var parentConnection = this; var parentBlock = parentConnection.SourceBlock; var childBlock = childConnection.SourceBlock; // Disconnect any existing parent on the child connection. if (childConnection.IsConnected) { childConnection.Disconnect(); } // Other connection is already connected to something. // Disconnect it and reattach it or bump it as needed. if (parentConnection.IsConnected) { Block orphanBlock = parentConnection.TargetBlock; XmlNode shadowDom = parentConnection.ShadowDom; parentConnection.ShadowDom = null; if (orphanBlock.IsShadow) { // Save the shadow block so that field values are preserved. shadowDom = Xml.BlockToDom(orphanBlock); orphanBlock.Dispose(); orphanBlock = null; } else if (parentConnection.Type == Define.EConnection.InputValue) { //value connnections if (orphanBlock.OutputConnection == null) { throw new Exception("Orphan block does not have an output connection."); } // Attempt to reattach the orphan at the end of the newly inserted // block. Since this block may be a row, walk down to the end // or to the first (and only) shadow block. var connection = Connection.LastConnectionInRow(childBlock, orphanBlock); if (connection != null) { orphanBlock.OutputConnection.Connect(connection); orphanBlock = null; } } else if (parentConnection.Type == Define.EConnection.NextStatement) { // Statement connections. // Statement blocks may be inserted into the middle of a stack. // Split the stack. if (orphanBlock.PreviousConnection == null) { throw new Exception("Orphan block does not have a previous connection."); } // Attempt to reattach the orphan at the bottom of the newly inserted // block. Since this block may be a stack, walk down to the end. var newBlock = childBlock; while (newBlock.NextConnection != null) { var nextBlock = newBlock.NextBlock; if (nextBlock != null && !nextBlock.IsShadow) { newBlock = nextBlock; } else { if (orphanBlock.PreviousConnection.CheckType(newBlock.NextConnection)) { newBlock.NextConnection.Connect(orphanBlock.PreviousConnection); orphanBlock = null; } break; } } } if (orphanBlock != null) { // Unable to reattach orphan. parentConnection.Disconnect(); Connection orphanBlockCon = orphanBlock.OutputConnection != null ? orphanBlock.OutputConnection : orphanBlock.PreviousConnection; orphanBlockCon.FireUpdate(UpdateState.BumpedAway); } // Restore the shadow DOM. parentConnection.ShadowDom = shadowDom; } // Establish the connections. Connection.ConnectReciprocally(parentConnection, childConnection); // Demote the inferior block so that one is a child of the superior one. childBlock.SetParent(parentBlock); FireUpdate(UpdateState.Connected); }