Ejemplo n.º 1
0
        /// <summary>
        /// Adds a hierarchical list of resources to the combobox, simulating the tree structure with indents.
        /// Also supports folders in the tree, which are the resources of some other type but the target type.
        /// The main resources are filtered against an intersection list.
        /// </summary>
        /// <param name="resRoot">The root resource from which the tree enumeration starts. May be excluded from the tree (<paramref name="bAddRoot"/>).</param>
        /// <param name="resItemType">Resource type of the main resources. Note that the root resource may have some other type.</param>
        /// <param name="resFolderType">Type of the folder resources. They are not filtered against the intersection list. May be <c>Null</c> if no folders are expected.</param>
        /// <param name="propParent">The child-parent link type.</param>
        /// <param name="nStartIndent">Indent of the tree root (if included), or the first-level root's children (if the root is not included).
        /// Each next level is indented by 16 pixels against the parent one.
        /// The default value is <c>0</c>.</param>
        /// <param name="resIntersect">A resource list that filters out the main resources (does not affect folders and root).
        /// Only those resources that are present in the list are allowed into the tree.
        /// Children of a dropped resource are also dropped.
        /// The list is not instantiated, only its predicate is used.</param>
        /// <param name="bAddRoot">Whether to add the root resource passed as <paramref name="resRoot"/>.
        /// If the root is present (<c>True</c>), it has the <paramref name="nStartIndent"/> indent and its first-level children are indented by 16 pixels.
        /// If the root is not present (<c>False</c>), the first-level children are added with the root indent (<paramref name="nStartIndent"/>).</param>
        /// <param name="bSuppressEmptyFolders">If <c>True</c>, the empty folders (resources of folder type) are suppressed and not added
        /// into the tree. Has no effect on main resources and tree root, or when <paramref name="resFolderType"/> is <c>Null</c>.</param>
        public void AddFolderedResourceTree(IResource resRoot, string resItemType, string resFolderType, int propParent, int nStartIndent, IResourceList resIntersect, bool bAddRoot, bool bSuppressEmptyFolders)
        {
            if ((resRoot == null) || (resItemType == null))
            {
                throw new ArgumentNullException();
            }

            ArrayList arItems       = new ArrayList(); // Caches items before they get added to the list; some items may get removed from here
            ArrayList arEnums       = new ArrayList(); // Enumerations stack
            HashSet   hashEverAdded = new HashSet();   // A hash-set of all the items to avoid cyclic links

            // Seed the enumeration
            arEnums.Add(resRoot.ToResourceList().GetEnumerator());

            // Collect the items
            for (; arEnums.Count != 0;)
            {
                IEnumerator enumCurrent = (IEnumerator)arEnums[arEnums.Count - 1];
                // Try to pick the next item, move to the upper level if unavailable
                if (!enumCurrent.MoveNext())
                {
                    // Pop to the upper level by removing the current enumerator from the stack
                    arEnums.RemoveAt(arEnums.Count - 1);

                    // Empty folder check: if the last-added item is the parent-level folder, drop it
                    if ((bSuppressEmptyFolders) && (arItems.Count > 0))
                    {
                        TempListItem tli = ((TempListItem)arItems[arItems.Count - 1]);
                        if ((tli.Resource.Type == resFolderType) && (tli.Indent == arEnums.Count - 1))
                        {
                            arItems.RemoveAt(arItems.Count - 1);
                        }
                    }
                    continue;             // Go on dealing with the upper-level enumerator
                }

                // Add the current item
                IResource resCurrent = (IResource)enumCurrent.Current;
                if (hashEverAdded.Contains(resCurrent))
                {
                    continue;             // Skip the already-visited items (avoid cyclic links)
                }
                if (!(
                        ((resCurrent == resRoot) ||
                         (resCurrent.Type == resFolderType) ||
                         ((resCurrent.Type == resItemType) && ((resIntersect == null) || (resIntersect.Contains(resCurrent)))))
                        ))
                {
                    continue;             // Allow only root, folder type and item type; for item type, check the intersect list (if specified)
                }
                // Add the item (root will be suppressed later)
                arItems.Add(new TempListItem(resCurrent, arEnums.Count - 1));
                hashEverAdded.Add(resCurrent);

                // Recurse to the item's children
                IResourceList listChildren = resCurrent.GetLinksTo(resItemType, propParent);
                if (resFolderType != null)
                {
                    listChildren = listChildren.Union(resCurrent.GetLinksTo(resFolderType, propParent));
                }
                listChildren.Sort("RootSortOrder", true);

                arEnums.Add(listChildren.GetEnumerator());         // Add a new enumerator to the stack
            }

            // Add the items
            foreach (TempListItem tli in arItems)
            {
                if ((!bAddRoot) && (tli.Resource == resRoot))
                {
                    continue;             // Do not add the root if prohibited
                }
                Items.Add(tli.Resource);
                SetItemIndent(tli.Resource, nStartIndent + (tli.Indent - (bAddRoot ? 0 : 1)) * 16);         // Decrease all the indents if there's no root
            }
        }