/// <summary>
        /// Checks if a given element in the tree view needs updating
        /// </summary>
        /// <param name="node">The node to check for</param>
        /// <param name="browser">The browser instance to check in</param>
        /// <returns>a tree view node based on the new data.</returns>
        private static KmlTreeViewNode UpdateCheck(KmlTreeViewNode node, GEWebBrowser browser)
        {
            dynamic liveObject = null;

            try
            {
                liveObject = browser.Plugin.getElementByUrl(node.Name);
            }
            catch (COMException)
            {
            }

            if (liveObject != null)
            {
                KmlTreeViewNode newNode = new KmlTreeViewNode(liveObject)
                {
                    Name = node.Name, BaseUrl = node.BaseUrl
                };

                if (node.Parent != null)
                {
                    // update the tree
                    node.Parent.Nodes.Insert(node.Index, newNode);
                    node.Parent.Nodes.Remove(node);
                }

                return(newNode);
            }

            return(node);
        }
        /// <summary>
        /// Sets the StateImageIndex of each child node of the given <paramref name="node">parent tree node</paramref>
        /// </summary>
        /// <param name="node">The parent tree node</param>
        private void SetChildStateImageIndex(KmlTreeViewNode node)
        {
            foreach (KmlTreeViewNode child in node.Nodes)
            {
                if (child.StateImageIndex == -1)
                {
                    child.StateImageIndex = child.Checked ? 1 : 0;
                }
            }

            this.Refresh();
        }
        /// <summary>
        ///  Returns the index of the first occurrence of a tree node with the specified object ID.
        ///  As the node key is automatically set from the kmlObject ID the IDs should always correspond and be unique.
        /// </summary>
        /// <param name="id">The API object id</param>
        /// <returns>The tree node for the object from the given ID (or an empty tree node if the ID isn't found)</returns>
        public KmlTreeViewNode GetNodeById(string id)
        {
            TreeNode[]      nodes = this.Nodes.Find(id, true);
            KmlTreeViewNode node  = new KmlTreeViewNode();

            if (nodes.Length == 1)
            {
                node = (KmlTreeViewNode)nodes[0];
            }

            return(node);
        }
        /// <summary>
        /// Adds children to a KmlTreeViewNode.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">Event arguments.</param>
        private void NodeBuilderRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Result == null)
            {
                return;
            }

            // the result object from NodeBuilder_DoWork
            object[]                result   = (object[])e.Result;
            KmlTreeViewNode         baseNode = (KmlTreeViewNode)result[0];
            Stack <KmlTreeViewNode> children = (Stack <KmlTreeViewNode>)result[1];
            bool linkFailed = Convert.ToBoolean(result[2], CultureInfo.InvariantCulture);

            // clear the node of all children
            baseNode.Nodes.Clear();

            // add the children to the node
            // (is just a new placeholder if there was error loading a network link)
            while (children.Count > 0)
            {
                KmlTreeViewNode child = children.Pop();
                baseNode.Nodes.Add(child);

                // If the parent has a BaseUrl then we need to use this to generate the
                // correct ids for the child, we also set the `baseurl` on the child for its children ...
                // we also do an update check as it is possible the node needs to be updated...
                string url = child.Parent.BaseUrl;

                if (!string.IsNullOrEmpty(url) && child.ApiObject != null)
                {
                    child.Name    = GenerateId(url, child.ApiObject.getId());
                    child.BaseUrl = url;
                    UpdateCheck(child, this.browser);
                }
            }

            if (linkFailed)
            {
                baseNode.Collapse();
                baseNode.ImageKey = baseNode.SelectedImageKey = "linkFolderClosedDisconected";
            }
            else
            {
                this.SetChildStateImageIndex(baseNode);
            }
        }
        /// <summary>
        /// Raised when a KmlTreeView node is double clicked
        /// </summary>
        /// <param name="e">Event arguments</param>
        protected override void OnNodeMouseDoubleClick(TreeNodeMouseClickEventArgs e)
        {
            base.OnNodeMouseDoubleClick(e);

            // check if the node needs updating...
            // ideally this should be event driven rather than via user interaction
            // but as yet the API does not expose network link events...
            KmlTreeViewNode node =
                UpdateCheck((KmlTreeViewNode)e.Node, this.browser);

            node.Refresh();

            if (node.IsLoading)
            {
                return;
            }

            switch (node.ApiType)
            {
            case ApiType.KmlPlacemark:
            case ApiType.KmlFolder:
            case ApiType.KmlDocument:
            case ApiType.KmlGroundOverlay:
            {
                GEHelpers.OpenFeatureBalloon(this.browser.Plugin, node.ApiObject, setBalloon: node.Checked);
            }

            break;

            case ApiType.KmlTour:
            case ApiType.KmlPhotoOverlay:
            {
                GEHelpers.ToggleMediaPlayer(this.browser.Plugin, node.ApiObject, node.Checked);
            }

                return;       // exit here as the media player handles the view update

            case ApiType.None:
                return;
            }

            GEHelpers.FlyToObject(this.browser.Plugin, node.ApiObject);
        }
        /// <summary>
        /// Refreshes and updates the layout of the control
        /// </summary>
        public override void Refresh()
        {
            base.Refresh();
            this.BeginUpdate();

            if (!this.CheckBoxes)
            {
                return;
            }

            base.CheckBoxes = false;

            Stack <KmlTreeViewNode> stack =
                new Stack <KmlTreeViewNode>(this.Nodes.Count);

            foreach (KmlTreeViewNode node in this.Nodes)
            {
                // Refresh internal properties of each node
                // http://code.google.com/p/winforms-geplugin-control-library/issues/detail?id=66
                node.Refresh();
                stack.Push(node);
            }

            while (stack.Count > 0)
            {
                KmlTreeViewNode node = stack.Pop();

                if (node.StateImageIndex == -1)
                {
                    node.StateImageIndex = node.Checked ? 1 : 0;
                }

                for (int i = 0; i < node.Nodes.Count; i++)
                {
                    stack.Push((KmlTreeViewNode)node.Nodes[i]);
                }
            }

            this.EndUpdate();
        }
        /// <summary>
        /// Raised after a KmlTreeViewNode is expanded
        /// </summary>
        /// <param name="e">Event arguments</param>
        protected override void OnAfterExpand(TreeViewEventArgs e)
        {
            base.OnAfterExpand(e);

            KmlTreeViewNode eventNode = (KmlTreeViewNode)e.Node;

            eventNode.SetStyle();

            // If there is a place-holder node
            if (eventNode.Nodes.ContainsKey(ApiType.None.ToString()))
            {
                if (eventNode.IsLoading)
                {
                    return;
                }

                // animate the place holder
                int index = eventNode.Nodes.IndexOfKey(ApiType.None.ToString());
                ((KmlTreeViewNode)eventNode.Nodes[index]).Animate();

                // set up the background worker
                // ...using named delegates to stop code clutter here
                using (BackgroundWorker nodeBuilder = new BackgroundWorker())
                {
                    nodeBuilder.DoWork             += this.NodeBuilderDoWork;
                    nodeBuilder.RunWorkerCompleted += this.NodeBuilderRunWorkerCompleted;
                    nodeBuilder.RunWorkerAsync(eventNode);
                }
            }
            else
            {
                // There is no place-holder node...
                // so just set the check state of the children
                this.SetChildStateImageIndex(eventNode);
            }
        }
        /// <summary>
        /// Creates a KmlTreeViewNode from an KML feature
        /// </summary>
        /// <param name="feature">The KML feature to base the node on</param>
        /// <returns>A KmlTreeViewNode based on the feature</returns>
        public static KmlTreeViewNode CreateNode(dynamic feature)
        {
            // create the node from the feature
            KmlTreeViewNode treeNode = new KmlTreeViewNode(feature);

            // if the children are hidden just return the empty node...
            if (treeNode.KmlListStyle == ListItemStyle.CheckHideChildren)
            {
                return(treeNode);
            }

            // if the node is a network link or a document or folder
            // and it has children...
            if (treeNode.ApiType == ApiType.KmlNetworkLink ||
                ((treeNode.ApiType == ApiType.KmlDocument ||
                  treeNode.ApiType == ApiType.KmlFolder) &&
                 KmlHelpers.HasChildNodes(feature)))
            {
                // add a place holder for the children...
                treeNode.Nodes.Add(new KmlTreeViewNode());
            }

            return(treeNode);
        }
        /// <summary>
        /// Asynchronous method for building a list of nodes
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">Event arguments.</param>
        private void NodeBuilderDoWork(object sender, DoWorkEventArgs e)
        {
            // node passed in from RunWorkerAsync
            KmlTreeViewNode baseNode = (KmlTreeViewNode)e.Argument;

            baseNode.IsLoading = true;

            // create a stack to hold the children we will create
            Stack <KmlTreeViewNode> children = new Stack <KmlTreeViewNode>();
            bool linkFailed = false;

            if (baseNode.ApiType == ApiType.KmlNetworkLink)
            {
                // fetch the network link data
                string  url = KmlHelpers.GetUrl(baseNode.ApiObject).ToString();
                dynamic data;
                bool    rebuild = false;

                // can't use the new FetchAndParse with archive files...
                if (url.EndsWith("kmz", StringComparison.OrdinalIgnoreCase) ||
                    url.EndsWith("dae", StringComparison.OrdinalIgnoreCase))
                {
                    data = this.browser.FetchKmlSynchronous(url);
                }
                else
                {
                    data    = this.browser.FetchAndParse(url);
                    rebuild = true;
                }

                if (data != null)
                {
                    KmlTreeViewNode link = CreateNode(data);

                    if (rebuild)
                    {
                        // The KmlObjects are created via parseKml so they need their id's need to be rebuilt
                        // so that the Url is still present (e.g. http://foo.com/#id vs. #id)
                        // the `baseurl` of the node is set so that any child nodes can also have there id's rebuilt
                        // when they are created.
                        link.Name    = GenerateId(url, data.getId());
                        link.BaseUrl = url;
                    }

                    // create a new tree node from the data and push it on to the stack
                    children.Push(link);
                }
                else
                {
                    // no data, so push a new place holder node in and set the loadError flag
                    baseNode.IsLoading = false;
                    children.Push(new KmlTreeViewNode());
                    linkFailed = true;
                }
            }
            else
            {
                // the feature must be a KmlFolder or a KmlDocument (KmlContainer)
                // ...so get the child nodes from it
                dynamic kmlChildNodes = KmlHelpers.GetChildNodes(baseNode.ApiObject);

                if (kmlChildNodes != null)
                {
                    int count = kmlChildNodes.getLength();
                    for (int i = 0; i < count; i++)
                    {
                        // create a new KmlTreeViewNode from each feature in the KmlContainer
                        // and push it on to the stack.
                        try
                        {
                            children.Push(CreateNode(kmlChildNodes.item(i)));
                        }
                        catch (COMException)
                        {
                            children.Clear();
                            return;
                        }
                    }
                }
            }

            // pass the base node, child stack and error flag as the result.
            e.Result = new object[] { baseNode, children, linkFailed };
        }
        /// <summary>
        /// Raised when the mouse is clicked on the KmlTreeView
        /// </summary>
        /// <param name="e">The event arguments</param>
        protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
        {
            base.OnNodeMouseClick(e);
            this.preventChecking = true;

            int space = this.ImageList == null ? 0 : 18;

            if ((e.X > e.Node.Bounds.Left - space ||
                 e.X < e.Node.Bounds.Left - (space + 16)) &&
                e.Button != MouseButtons.None)
            {
                return;
            }

            KmlTreeViewNode treeNode = (KmlTreeViewNode)e.Node;

            if (e.Button == MouseButtons.Left)
            {
                // toggle the check state
                treeNode.Checked          = !treeNode.Checked;
                treeNode.ApiObjectVisible = treeNode.Checked;

                if (!treeNode.Checked)
                {
                    // Turn off the media player for the node if it was unchecked
                    // For example, un-checking a Tour object in the tree exits the tour player
                    GEHelpers.ToggleMediaPlayer(this.browser.Plugin, treeNode.ApiObject, false);
                }
            }

            treeNode.StateImageIndex = treeNode.Checked ? 1 : treeNode.StateImageIndex;

            this.OnAfterCheck(new TreeViewEventArgs(treeNode, TreeViewAction.ByMouse));

            Stack <KmlTreeViewNode> nodes = new Stack <KmlTreeViewNode>(treeNode.Nodes.Count);

            nodes.Push(treeNode);

            do
            {
                treeNode                  = nodes.Pop();
                treeNode.Checked          = e.Node.Checked;
                treeNode.ApiObjectVisible = treeNode.Checked;
                for (int i = 0; i < treeNode.Nodes.Count; i++)
                {
                    nodes.Push((KmlTreeViewNode)treeNode.Nodes[i]);
                }
            }while (nodes.Count > 0);

            bool state = false;

            treeNode = (KmlTreeViewNode)e.Node;

            while (treeNode.Parent != null)
            {
                foreach (KmlTreeViewNode child in treeNode.Parent.Nodes)
                {
                    state |= child.Checked != treeNode.Checked | child.StateImageIndex == 2;
                }

                int index = (int)Convert.ToUInt32(treeNode.Checked);
                treeNode.Parent.Checked = state || (index > 0);

                if (state)
                {
                    treeNode.Parent.ApiObjectVisible = true;
                    treeNode.Parent.StateImageIndex  = 2;
                }
                else
                {
                    treeNode.Parent.StateImageIndex = index;
                }

                treeNode = treeNode.Parent;
            }

            this.preventChecking = false;
        }
        /// <summary>
        /// Sets the StateImageIndex of each child node of the given <paramref name="node">parent tree node</paramref>
        /// </summary>
        /// <param name="node">The parent tree node</param>
        private void SetChildStateImageIndex(KmlTreeViewNode node)
        {
            foreach (KmlTreeViewNode child in node.Nodes)
            {
                if (child.StateImageIndex == -1)
                {
                    child.StateImageIndex = child.Checked ? 1 : 0;
                }
            }

            this.Refresh();
        }
        /// <summary>
        /// Checks if a given element in the tree view needs updating
        /// </summary>
        /// <param name="node">The node to check for</param>
        /// <param name="browser">The browser instance to check in</param>
        /// <returns>a tree view node based on the new data.</returns>
        private static KmlTreeViewNode UpdateCheck(KmlTreeViewNode node, GEWebBrowser browser)
        {
            dynamic liveObject = null;

            try
            {
                liveObject = browser.Plugin.getElementByUrl(node.Name);
            }
            catch (COMException)
            {
            }

            if (liveObject != null)
            {
                KmlTreeViewNode newNode = new KmlTreeViewNode(liveObject) { Name = node.Name, BaseUrl = node.BaseUrl };

                if (node.Parent != null)
                {
                    // update the tree
                    node.Parent.Nodes.Insert(node.Index, newNode);
                    node.Parent.Nodes.Remove(node);
                }

                return newNode;
            }

            return node;
        }
        /// <summary>
        ///  Returns the index of the first occurrence of a tree node with the specified object ID.
        ///  As the node key is automatically set from the kmlObject ID the IDs should always correspond and be unique.
        /// </summary>
        /// <param name="id">The API object id</param>
        /// <returns>The tree node for the object from the given ID (or an empty tree node if the ID isn't found)</returns>
        public KmlTreeViewNode GetNodeById(string id)
        {
            TreeNode[] nodes = this.Nodes.Find(id, true);
            KmlTreeViewNode node = new KmlTreeViewNode();

            if (nodes.Length == 1)
            {
                node = (KmlTreeViewNode)nodes[0];
            }

            return node;
        }
        /// <summary>
        /// Creates a KmlTreeViewNode from an KML feature 
        /// </summary>
        /// <param name="feature">The KML feature to base the node on</param>
        /// <returns>A KmlTreeViewNode based on the feature</returns>
        public static KmlTreeViewNode CreateNode(dynamic feature)
        {
            // create the node from the feature
            KmlTreeViewNode treeNode = new KmlTreeViewNode(feature);

            // if the children are hidden just return the empty node...
            if (treeNode.KmlListStyle == ListItemStyle.CheckHideChildren)
            {
                return treeNode;
            }

            // if the node is a network link or a document or folder
            // and it has children...
            if (treeNode.ApiType == ApiType.KmlNetworkLink ||
                ((treeNode.ApiType == ApiType.KmlDocument ||
                treeNode.ApiType == ApiType.KmlFolder) &&
                KmlHelpers.HasChildNodes(feature)))
            {
                // add a place holder for the children... 
                treeNode.Nodes.Add(new KmlTreeViewNode());
            }

            return treeNode;
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Creates a KmlTreeViewNode from an kml feature 
        /// </summary>
        /// <param name="feature">The kml feature to base the node on</param>
        /// <returns>A KmlTreeViewNode based on the feature</returns>
        public KmlTreeViewNode CreateNode(dynamic feature)
        {
            // create the node from the feature
            KmlTreeViewNode treeNode = new KmlTreeViewNode(feature);

            // if the node is a networlink, or
            // a document or folder with children
            if (treeNode.ApiType == ApiType.KmlNetworkLink ||
                ((treeNode.ApiType == ApiType.KmlDocument ||
                treeNode.ApiType == ApiType.KmlFolder) &&
                KmlHelpers.HasChildNodes(feature)))
            {
                // add a place holder
                treeNode.Nodes.Add(new KmlTreeViewNode());
            }

            return treeNode;
        }