Ejemplo n.º 1
0
        /// <summary>
        /// Encode a block subtree as XML.
        /// </summary>
        /// <param name="block">The root block to encode.</param>
        /// <param name="optNoId">True if the encoder should skip the block id.</param>
        /// <returns></returns>
        public static XmlNode BlockToDom(Block block, bool optNoId = false)
        {
            var element = XmlUtil.CreateDom(block.IsShadow ? "shadow" : "block");

            element.SetAttribute("type", block.Type);
            if (!optNoId)
            {
                element.SetAttribute("id", block.ID);
            }

            if (block.Mutator != null)
            {
                // Custom data for an advanced block.
                var container = block.Mutator.ToXml();
                if (container != null)
                {
                    element.AppendChild(container);
                }
            }

            Action <Field> fieldToDom = delegate(Field field)
            {
//                if  TODO: editable is true (!string.IsNullOrEmpty(field.Name) && field.Editable)
                if (!string.IsNullOrEmpty(field.Name))
                {
                    var container = XmlUtil.CreateDom("field", null, field.GetValue());
                    container.SetAttribute("name", field.Name);
                    if (field is FieldVariable)
                    {
                        var variable = block.Workspace.GetVariable(field.GetValue());
                        if (null != variable)
                        {
                            container.SetAttribute("id", variable.ID);
                            container.SetAttribute("variableType", variable.Type);
                        }
                    }
                    element.AppendChild(container);
                }
            };

            foreach (var input in block.InputList)
            {
                foreach (var field in input.FieldRow)
                {
                    fieldToDom(field);
                }
            }

            if (!string.IsNullOrEmpty(block.Data))
            {
                var dataElement = XmlUtil.CreateDom("data", null, block.Data);
                element.AppendChild(dataElement);
            }

            foreach (var input in block.InputList)
            {
                XmlNode container = null;
                var     empty     = true;
                if (input.Type == Define.EConnection.DummyInput)
                {
                    continue;
                }
                else
                {
                    var childBlock = input.Connection.TargetBlock;
                    if (input.Type == Define.EConnection.InputValue)
                    {
                        container = XmlUtil.CreateDom("value");
                    }
                    else if (input.Type == Define.EConnection.NextStatement)
                    {
                        container = XmlUtil.CreateDom("statement");
                    }

                    var shadow = input.Connection.ShadowDom;

                    if (null != shadow && (null == childBlock || !childBlock.IsShadow))
                    {
                        //        container.appendChild(Blockly.Xml.cloneShadow_(shadow));
                    }
                    if (null != childBlock)
                    {
                        container.AppendChild(Xml.BlockToDom(childBlock, optNoId));
                        empty = false;
                    }
                }
                container.SetAttribute("name", input.Name);

                if (!empty)
                {
                    element.AppendChild(container);
                }
            }

            if (block.Collapsed)
            {
                element.SetAttribute("collapsed", "true");
            }
            if (block.Disabled)
            {
                element.SetAttribute("disabled", "true");
            }
            if (!block.Deletable && !block.IsShadow)
            {
                element.SetAttribute("deletable", "false");
            }
            if (!block.Movable && !block.IsShadow)
            {
                element.SetAttribute("movable", "false");
            }
            if (!block.Editable)
            {
                element.SetAttribute("editable", "false");
            }

            var nextBlock = block.NextBlock;

            if (null != nextBlock)
            {
                var container = XmlUtil.CreateDom("next", null, BlockToDom(nextBlock, optNoId));
                element.AppendChild(container);
            }

            return(element);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Decode an XML block tag and crete a block (and possbly sub blocks) on the
        /// workspace.
        /// </summary>
        /// <param name="xmlBlock"> XML block element.</param>
        /// <param name="workspace"> The workspace</param>
        public static Block DomToBlockHeadless(XmlNode xmlBlock, Workspace workspace)
        {
            var   prototypeName = xmlBlock.GetAttribute("type");
            var   id            = xmlBlock.GetAttribute("id");
            Block block         = workspace.NewBlock(prototypeName, id);
            Block blockChild    = null;

            for (var i = 0; i < xmlBlock.ChildNodes.Count; i++)
            {
                var xmlChild = xmlBlock.ChildNodes[i];
                if (xmlChild.NodeType == (XmlNodeType)3)
                {
                    // Ignore any text at the <block>level. It's all whitespace anyway.
                    continue;
                }
                Input input = null;
                // Find any enclosed blocks or shadows in this tag.
                XmlNode childBlockNode  = null;
                XmlNode childShadowNode = null;
                for (var j = 0; j < xmlChild.ChildNodes.Count; j++)
                {
                    var grandchildNode = xmlChild.ChildNodes[j];
                    if (grandchildNode.NodeType == (XmlNodeType)1)
                    {
                        if (string.Equals(grandchildNode.NodeName().ToLower(), "block"))
                        {
                            childBlockNode = grandchildNode;
                        }
                        else if (string.Equals(grandchildNode.NodeName().ToLower(), "shadow"))
                        {
                            childShadowNode = grandchildNode;
                        }
                    }
                }
                // Use the shadow block if there is no child block.
                if (null == childBlockNode && null != childShadowNode)
                {
                    childBlockNode = childShadowNode;
                }

                var name = xmlChild.GetAttribute("name");
                switch (xmlChild.NodeName().ToLower())
                {
                case "mutation":
                    // Custom data for an advanced block.
                    if (block.Mutator != null)
                    {
                        block.Mutator.FromXml((XmlElement)xmlChild);
                    }
                    break;

                case "data":
                    block.Data = xmlChild.TextContent();
                    break;

                case "title":
                case "field":
                {
                    var field = block.GetField(name);
                    var text  = xmlChild.TextContent();
                    if (field is FieldVariable)
                    {
                        // TODO (marisaleung): When we change setValue and getValue to
                        // interact with id's instead of names,update this so that we get
                        // the variable based on id instead of textContent.
                        var type = string.IsNullOrEmpty(xmlChild.GetAttribute("variableType"))
                                ? xmlChild.GetAttribute("variableType")
                                : "";
                        var variable = workspace.GetVariable(text);
                        if (null == variable)
                        {
                            variable = workspace.CreateVariable(text, type, xmlChild.GetAttribute(id));
                        }

                        if (!string.IsNullOrEmpty(type))
                        {
                            if (!string.Equals(variable.Type, type))
                            {
                                throw new Exception("Serialized variable type with id \'" +
                                                    variable.ID + "\' had type " + variable.Type + ", and " +
                                                    "does not match variable field that references it: " +
                                                    Xml.DomToText(xmlChild) + ".");
                            }
                        }
                    }

                    if (null == field)
                    {
                        Console.WriteLine("Ignoring non-existent field " + name + " in block " + prototypeName);
                        break;
                    }
                    field.SetValue(text);
                }
                break;

                case "value":
                case "statement":
                    input = block.GetInput(name);
                    if (null == input)
                    {
                        Console.WriteLine("Ignoring non-existent input " + name + " in block " +
                                          prototypeName);
                        break;
                    }
                    if (null != childShadowNode)
                    {
//                            input.connection.setShadowDom(childShadowNode);
                    }
                    if (null != childBlockNode)
                    {
                        blockChild = Xml.DomToBlockHeadless(childBlockNode, workspace);
                        if (null != blockChild.OutputConnection)
                        {
                            input.Connection.Connect(blockChild.OutputConnection);
                        }
                        else if (null != blockChild.PreviousConnection)
                        {
                            input.Connection.Connect(blockChild.PreviousConnection);
                        }
                        else
                        {
                            throw new Exception("Child block does not have output or previous statement.");
                        }
                    }
                    break;

                case "next":
                    if (null != childShadowNode && null != block.NextConnection)
                    {
//                            block.nextConnection.setShadowDom(childShadowNode);
                    }
                    if (null != childBlockNode)
                    {
                        blockChild = Xml.DomToBlockHeadless(childBlockNode, workspace);
                        block.NextConnection.Connect(blockChild.PreviousConnection);
                    }
                    break;

                default:
                    // Unknown tag; ignore. Same principle as HTML parsers.
                    Console.WriteLine("Ignoring unknown tag: " + xmlChild.NodeName());
                    break;
                }
            }

            var inline = xmlBlock.GetAttribute("inline");

            if (!string.IsNullOrEmpty(inline))
            {
                block.SetInputsInline(string.Equals(inline, "true"));
            }
            var disabled = xmlBlock.GetAttribute("disabled");

            if (!string.IsNullOrEmpty(disabled))
            {
                block.Disabled = string.Equals(disabled, "true");
            }

            var deletable = xmlBlock.GetAttribute("deletable");

            if (!string.IsNullOrEmpty(deletable))
            {
                block.Deletable = string.Equals(deletable, "true");
            }

            var movable = xmlBlock.GetAttribute("movable");

            if (!string.IsNullOrEmpty(movable))
            {
                block.Movable = string.Equals(movable, "true");
            }

            var editable = xmlBlock.GetAttribute("editable");

            if (!string.IsNullOrEmpty(editable))
            {
                block.Editable = string.Equals(editable, "true");
            }

            var collapsed = xmlBlock.GetAttribute("collapsed");

            if (!string.IsNullOrEmpty(collapsed))
            {
                block.Collapsed = string.Equals(collapsed, "true");
            }
            return(block);
        }
Ejemplo n.º 3
0
        /// <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);
        }