/// <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 } }