using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using NBTExplorer.Model; using Substrate.Nbt; using NBTExplorer.Windows; using NBTExplorer.Vendor.MultiSelectTreeView; using System.IO; namespace NBTExplorer.Controllers { public class MessageBoxEventArgs : EventArgs { public bool Cancel { get; set; } public string Message { get; set; } public MessageBoxEventArgs (string message) { Message = message; } } public class NodeTreeController { private TreeView _nodeTree; private MultiSelectTreeView _multiTree; private IconRegistry _iconRegistry; //private TagCompoundDataNode _rootData; private RootDataNode _rootData; public NodeTreeController (TreeView nodeTree) { _nodeTree = nodeTree; _multiTree = nodeTree as MultiSelectTreeView; InitializeIconRegistry(); ShowVirtualRoot = true; //_rootData = new TagCompoundDataNode(new TagNodeCompound()); _rootData = new RootDataNode(); RefreshRootNodes(); } public RootDataNode Root { get { return _rootData; } } public TreeView Tree { get { return _nodeTree; } } public bool ShowVirtualRoot { get; set; } public string VirtualRootDisplay { get { return _rootData.NodeDisplay; } set { _rootData.SetDisplayName(value); if (ShowVirtualRoot && _nodeTree.Nodes.Count > 0) UpdateNodeText(_nodeTree.Nodes[0]); } } public event EventHandler SelectionInvalidated; protected virtual void OnSelectionInvalidated (EventArgs e) { if (SelectionInvalidated != null) SelectionInvalidated(this, e); } private void OnSelectionInvalidated () { OnSelectionInvalidated(EventArgs.Empty); } public event EventHandler ConfirmAction; protected virtual void OnConfirmAction (MessageBoxEventArgs e) { if (ConfirmAction != null) ConfirmAction(this, e); } private bool OnConfirmAction (string message) { MessageBoxEventArgs e = new MessageBoxEventArgs(message); OnConfirmAction(e); return !e.Cancel; } private TreeNode SelectedNode { get { if (_multiTree != null) return _multiTree.SelectedNode; else return _nodeTree.SelectedNode; } } #region Load / Save public void Save () { foreach (TreeNode node in _nodeTree.Nodes) { DataNode dataNode = node.Tag as DataNode; if (dataNode != null) dataNode.Save(); } OnSelectionInvalidated(); } public int OpenPaths (string[] paths) { _nodeTree.Nodes.Clear(); int failCount = 0; foreach (string path in paths) { if (Directory.Exists(path)) { DirectoryDataNode node = new DirectoryDataNode(path); _nodeTree.Nodes.Add(CreateUnexpandedNode(node)); } else if (File.Exists(path)) { DataNode node = null; foreach (var item in FileTypeRegistry.RegisteredTypes) { if (item.Value.NamePatternTest(path)) node = item.Value.NodeCreate(path); } if (node != null) _nodeTree.Nodes.Add(CreateUnexpandedNode(node)); else failCount++; } } if (_nodeTree.Nodes.Count > 0) { _nodeTree.Nodes[0].Expand(); } OnSelectionInvalidated(); return failCount; } #endregion public void CreateNode (TreeNode node, TagType type) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanCreateTag(type)) return; if (dataNode.CreateNode(type)) { node.Text = dataNode.NodeDisplay; RefreshChildNodes(node, dataNode); OnSelectionInvalidated(); } } public void CreateNode (TagType type) { if (_nodeTree.SelectedNode == null) return; CreateNode(_nodeTree.SelectedNode, type); } public void DeleteNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanDeleteNode) return; if (dataNode.DeleteNode()) { UpdateNodeText(node.Parent); node.Remove(); RemoveNodeFromSelection(node); OnSelectionInvalidated(); } } private bool DeleteNode (IList nodes) { bool? elideChildren = null; if (!CanOperateOnNodesEx(nodes, Predicates.DeleteNodePred, out elideChildren)) return false; if (elideChildren == true) nodes = ElideChildren(nodes); bool selectionModified = false; foreach (TreeNode node in nodes) { DataNode dataNode = node.Tag as DataNode; if (dataNode.DeleteNode()) { UpdateNodeText(node.Parent); node.Remove(); RemoveNodeFromSelection(node); selectionModified = true; } } if (selectionModified) OnSelectionInvalidated(); return true; } private bool RemoveNodeFromSelection (TreeNode node) { bool selectionModified = false; if (_multiTree != null) { if (_multiTree.SelectedNodes.Contains(node)) { _multiTree.SelectedNodes.Remove(node); selectionModified = true; } if (_multiTree.SelectedNode == node) { _multiTree.SelectedNode = null; selectionModified = true; } } if (_nodeTree.SelectedNode == node) { _nodeTree.SelectedNode = null; selectionModified = true; } return selectionModified; } public void DeleteSelection () { if (_multiTree != null) DeleteNode(_multiTree.SelectedNodes); else DeleteNode(SelectedNode); } public void EditNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanEditNode) return; if (dataNode.EditNode()) { node.Text = dataNode.NodeDisplay; OnSelectionInvalidated(); } } public void EditSelection () { EditNode(SelectedNode); } private void RenameNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanRenameNode) return; if (dataNode.RenameNode()) { node.Text = dataNode.NodeDisplay; OnSelectionInvalidated(); } } public void RenameSelection () { RenameNode(SelectedNode); } private void RefreshNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanRefreshNode) return; if (!OnConfirmAction("Refresh data anyway?")) return; if (dataNode.RefreshNode()) { RefreshChildNodes(node, dataNode); ExpandToEdge(node); OnSelectionInvalidated(); } } public void RefreshSelection () { RefreshNode(SelectedNode); } private void ExpandToEdge (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (dataNode.IsExpanded) { if (!node.IsExpanded) node.Expand(); foreach (TreeNode child in node.Nodes) ExpandToEdge(child); } } private void CopyNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanCopyNode) return; dataNode.CopyNode(); } private void CutNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanCutNode) return; if (dataNode.CutNode()) { UpdateNodeText(node.Parent); node.Remove(); RemoveNodeFromSelection(node); OnSelectionInvalidated(); } } private void PasteNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; if (!dataNode.CanPasteIntoNode) return; if (dataNode.PasteNode()) { node.Text = dataNode.NodeDisplay; RefreshChildNodes(node, dataNode); OnSelectionInvalidated(); } } public void CopySelection () { CopyNode(SelectedNode); } public void CutSelection () { CutNode(SelectedNode); } public void PasteIntoSelection () { PasteNode(SelectedNode); } public void MoveNodeUp (TreeNode node) { if (node == null) return; DataNode datanode = node.Tag as DataNode; if (datanode == null || !datanode.CanMoveNodeUp) return; if (datanode.ChangeRelativePosition(-1)) { RefreshChildNodes(node.Parent, datanode.Parent); OnSelectionInvalidated(); } } public void MoveNodeDown (TreeNode node) { if (node == null) return; DataNode datanode = node.Tag as DataNode; if (datanode == null || !datanode.CanMoveNodeDown) return; if (datanode.ChangeRelativePosition(1)) { RefreshChildNodes(node.Parent, datanode.Parent); OnSelectionInvalidated(); } } public void MoveSelectionUp () { MoveNodeUp(SelectedNode); } public void MoveSelectionDown () { MoveNodeDown(SelectedNode); } /*public void CreateRootNode (TagType type) { if (_rootData.CreateNode(type)) { RefreshRootNodes(); UpdateUI(_rootData); } }*/ public void ExpandNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; if (node.IsExpanded) return; node.Nodes.Clear(); DataNode backNode = node.Tag as DataNode; if (!backNode.IsExpanded) { backNode.Expand(); node.Text = backNode.NodeDisplay; } foreach (DataNode child in backNode.Nodes) node.Nodes.Add(CreateUnexpandedNode(child)); } public void ExpandSelectedNode () { ExpandNode(SelectedNode); if (SelectedNode != null) SelectedNode.Expand(); } public void CollapseNode (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode backNode = node.Tag as DataNode; if (backNode.IsModified) return; backNode.Collapse(); node.Name = backNode.NodeDisplay; node.Nodes.Clear(); if (backNode.HasUnexpandedChildren) node.Nodes.Add(new TreeNode()); } public void CollapseSelectedNode () { CollapseNode(SelectedNode); } private TreeNode GetRootFromDataNodePath (DataNode node, out Stack hierarchy) { hierarchy = new Stack(); while (node != null) { hierarchy.Push(node); node = node.Parent; } DataNode rootDataNode = hierarchy.Pop(); TreeNode frontNode = null; foreach (TreeNode child in _nodeTree.Nodes) { if (child.Tag == rootDataNode) frontNode = child; } return frontNode; } private TreeNode FindFrontNode (DataNode node) { Stack hierarchy; TreeNode frontNode = GetRootFromDataNodePath(node, out hierarchy); if (frontNode == null) return null; while (hierarchy.Count > 0) { if (!frontNode.IsExpanded) { frontNode.Nodes.Add(new TreeNode()); frontNode.Expand(); } DataNode childData = hierarchy.Pop(); foreach (TreeNode childFront in frontNode.Nodes) { if (childFront.Tag == childData) { frontNode = childFront; break; } } } return frontNode; } public void CollapseBelow (DataNode node) { Stack hierarchy; TreeNode frontNode = GetRootFromDataNodePath(node, out hierarchy); if (frontNode == null) return; while (hierarchy.Count > 0) { if (!frontNode.IsExpanded) return; DataNode childData = hierarchy.Pop(); foreach (TreeNode childFront in frontNode.Nodes) { if (childFront.Tag == childData) { frontNode = childFront; break; } } } if (frontNode.IsExpanded) frontNode.Collapse(); } public void SelectNode (DataNode node) { if (_multiTree != null) { _multiTree.SelectedNode = FindFrontNode(node); } else { _nodeTree.SelectedNode = FindFrontNode(node); } } public void RefreshRootNodes () { if (ShowVirtualRoot) { _nodeTree.Nodes.Clear(); _nodeTree.Nodes.Add(CreateUnexpandedNode(_rootData)); return; } if (_rootData.HasUnexpandedChildren) _rootData.Expand(); Dictionary currentNodes = new Dictionary(); foreach (TreeNode child in _nodeTree.Nodes) { if (child.Tag is DataNode) currentNodes.Add(child.Tag as DataNode, child); } _nodeTree.Nodes.Clear(); foreach (DataNode child in _rootData.Nodes) { if (!currentNodes.ContainsKey(child)) _nodeTree.Nodes.Add(CreateUnexpandedNode(child)); else _nodeTree.Nodes.Add(currentNodes[child]); } //if (_nodeTree.Nodes.Count == 0 && _rootData.HasUnexpandedChildren) { // _rootData.Expand(); // RefreshRootNodes(); //} } public void RefreshChildNodes (TreeNode node, DataNode dataNode) { Dictionary currentNodes = new Dictionary(); foreach (TreeNode child in node.Nodes) { if (child.Tag is DataNode) currentNodes.Add(child.Tag as DataNode, child); } node.Nodes.Clear(); foreach (DataNode child in dataNode.Nodes) { if (!currentNodes.ContainsKey(child)) node.Nodes.Add(CreateUnexpandedNode(child)); else node.Nodes.Add(currentNodes[child]); } foreach (TreeNode child in node.Nodes) child.ContextMenuStrip = BuildNodeContextMenu(child, child.Tag as DataNode); if (node.Nodes.Count == 0 && dataNode.HasUnexpandedChildren) { ExpandNode(node); node.Expand(); } } public void RefreshTreeNode (DataNode dataNode) { TreeNode node = FindFrontNode(dataNode); RefreshChildNodes(node, dataNode); } private void InitializeIconRegistry () { _iconRegistry = new IconRegistry(); _iconRegistry.DefaultIcon = 15; _iconRegistry.Register(typeof(TagByteDataNode), 0); _iconRegistry.Register(typeof(TagShortDataNode), 1); _iconRegistry.Register(typeof(TagIntDataNode), 2); _iconRegistry.Register(typeof(TagLongDataNode), 3); _iconRegistry.Register(typeof(TagFloatDataNode), 4); _iconRegistry.Register(typeof(TagDoubleDataNode), 5); _iconRegistry.Register(typeof(TagByteArrayDataNode), 6); _iconRegistry.Register(typeof(TagStringDataNode), 7); _iconRegistry.Register(typeof(TagListDataNode), 8); _iconRegistry.Register(typeof(TagCompoundDataNode), 9); _iconRegistry.Register(typeof(RegionChunkDataNode), 9); _iconRegistry.Register(typeof(DirectoryDataNode), 10); _iconRegistry.Register(typeof(RegionFileDataNode), 11); _iconRegistry.Register(typeof(CubicRegionDataNode), 11); _iconRegistry.Register(typeof(NbtFileDataNode), 12); _iconRegistry.Register(typeof(TagIntArrayDataNode), 14); _iconRegistry.Register(typeof(RootDataNode), 16); } private void UpdateNodeText (TreeNode node) { if (node == null || !(node.Tag is DataNode)) return; DataNode dataNode = node.Tag as DataNode; node.Text = dataNode.NodeDisplay; } public bool CheckModifications () { foreach (TreeNode node in _nodeTree.Nodes) { DataNode dataNode = node.Tag as DataNode; if (dataNode != null && dataNode.IsModified) return true; } return false; } private TreeNode CreateUnexpandedNode (DataNode node) { TreeNode frontNode = new TreeNode(node.NodeDisplay); frontNode.ImageIndex = _iconRegistry.Lookup(node.GetType()); frontNode.SelectedImageIndex = frontNode.ImageIndex; frontNode.Tag = node; //frontNode.ContextMenuStrip = BuildNodeContextMenu(node); if (node.HasUnexpandedChildren || node.Nodes.Count > 0) frontNode.Nodes.Add(new TreeNode()); return frontNode; } public ContextMenuStrip BuildNodeContextMenu (TreeNode frontNode, DataNode node) { if (node == null) return null; ContextMenuStrip menu = new ContextMenuStrip(); if (node.HasUnexpandedChildren || node.Nodes.Count > 0) { if (frontNode.IsExpanded) { ToolStripMenuItem itemCollapse = new ToolStripMenuItem("&Collapse", null, _contextCollapse_Click); itemCollapse.Font = new System.Drawing.Font(itemCollapse.Font, System.Drawing.FontStyle.Bold); ToolStripMenuItem itemExpandChildren = new ToolStripMenuItem("Expand C&hildren", null, _contextExpandChildren_Click); ToolStripMenuItem itemExpandTree = new ToolStripMenuItem("Expand &Tree", null, _contextExpandTree_Click); menu.Items.AddRange(new ToolStripItem[] { itemCollapse, new ToolStripSeparator(), itemExpandChildren, itemExpandTree, }); } else { ToolStripMenuItem itemExpand = new ToolStripMenuItem("&Expand", null, _contextExpand_Click); itemExpand.Font = new System.Drawing.Font(itemExpand.Font, System.Drawing.FontStyle.Bold); menu.Items.Add(itemExpand); } } if (node.CanReoderNode) { ToolStripMenuItem itemUp = new ToolStripMenuItem("Move &Up", Properties.Resources.ArrowUp, _contextMoveUp_Click); ToolStripMenuItem itemDn = new ToolStripMenuItem("Move &Down", Properties.Resources.ArrowDown, _contextMoveDown_Click); itemUp.Enabled = node.CanMoveNodeUp; itemDn.Enabled = node.CanMoveNodeDown; menu.Items.Add(itemUp); menu.Items.Add(itemDn); } return (menu.Items.Count > 0) ? menu : null; } private void _contextCollapse_Click (object sender, EventArgs e) { if (_multiTree.SelectedNode != null) _multiTree.SelectedNode.Collapse(); } private void _contextExpand_Click (object sender, EventArgs e) { if (_multiTree.SelectedNode != null) _multiTree.SelectedNode.Expand(); } private void _contextExpandChildren_Click (object sender, EventArgs e) { if (_multiTree.SelectedNode != null) { foreach (TreeNode node in _multiTree.SelectedNode.Nodes) node.Expand(); } } private void _contextExpandTree_Click (object sender, EventArgs e) { if (_multiTree.SelectedNode != null) { _multiTree.SelectedNode.ExpandAll(); } } private void _contextMoveUp_Click (object sender, EventArgs e) { MoveSelectionUp(); } private void _contextMoveDown_Click (object sender, EventArgs e) { MoveSelectionDown(); } #region Capability Checking #region Capability Predicates public delegate bool DataNodePredicate (DataNode dataNode, out GroupCapabilities caps); public static class Predicates { public static bool CreateByteNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_BYTE); } public static bool CreateShortNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_SHORT); } public static bool CreateIntNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_INT); } public static bool CreateLongNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_LONG); } public static bool CreateFloatNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_FLOAT); } public static bool CreateDoubleNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_DOUBLE); } public static bool CreateByteArrayNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_BYTE_ARRAY); } public static bool CreateIntArrayNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_INT_ARRAY); } public static bool CreateStringNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_STRING); } public static bool CreateListNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_LIST); } public static bool CreateCompoundNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = GroupCapabilities.Single; return (dataNode != null) && dataNode.CanCreateTag(TagType.TAG_COMPOUND); } public static bool RenameNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.RenameNodeCapabilities; return (dataNode != null) && dataNode.CanRenameNode; } public static bool EditNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.EditNodeCapabilities; return (dataNode != null) && dataNode.CanEditNode; } public static bool DeleteNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.DeleteNodeCapabilities; return (dataNode != null) && dataNode.CanDeleteNode; } public static bool MoveNodeUpPred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.ReorderNodeCapabilities; return (dataNode != null) && dataNode.CanMoveNodeUp; } public static bool MoveNodeDownPred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.ReorderNodeCapabilities; return (dataNode != null) && dataNode.CanMoveNodeDown; } public static bool CutNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.CutNodeCapabilities; return (dataNode != null) && dataNode.CanCutNode; } public static bool CopyNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.CopyNodeCapabilities; return (dataNode != null) && dataNode.CanCopyNode; } public static bool PasteIntoNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.PasteIntoNodeCapabilities; return (dataNode != null) && dataNode.CanPasteIntoNode; } public static bool SearchNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.SearchNodeCapabilites; return (dataNode != null) && dataNode.CanSearchNode; } public static bool ReorderNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.ReorderNodeCapabilities; return (dataNode != null) && dataNode.CanReoderNode; } public static bool RefreshNodePred (DataNode dataNode, out GroupCapabilities caps) { caps = dataNode.RefreshNodeCapabilites; return (dataNode != null) && dataNode.CanRefreshNode; } } #endregion public bool CanOperateOnSelection (DataNodePredicate pred) { if (_multiTree != null) return CanOperateOnNodes(_multiTree.SelectedNodes, pred); else return CanOperateOnNodes(new List() { _nodeTree.SelectedNode }, pred); } private bool CanOperateOnNodes (IList nodes, DataNodePredicate pred) { bool? elideChildren = null; return CanOperateOnNodesEx(nodes, pred, out elideChildren); } private bool CanOperateOnNodesEx (IList nodes, DataNodePredicate pred, out bool? elideChildren) { GroupCapabilities caps = GroupCapabilities.All; elideChildren = null; foreach (TreeNode node in nodes) { if (node == null || !(node.Tag is DataNode)) return false; DataNode dataNode = node.Tag as DataNode; GroupCapabilities dataCaps; if (!pred(dataNode, out dataCaps)) return false; caps &= dataCaps; bool elideChildrenFlag = (dataNode.DeleteNodeCapabilities & GroupCapabilities.ElideChildren) == GroupCapabilities.ElideChildren; if (elideChildren == null) elideChildren = elideChildrenFlag; if (elideChildren != elideChildrenFlag) return false; } if (nodes.Count > 1 && !SufficientCapabilities(nodes, caps)) return false; return true; } private IList ElideChildren (IList nodes) { List filtered = new List(); foreach (TreeNode node in nodes) { TreeNode parent = node.Parent; bool foundParent = false; while (parent != null) { if (nodes.Contains(parent)) { foundParent = true; break; } parent = parent.Parent; } if (!foundParent) filtered.Add(node); } return filtered; } private bool CommonContainer (IEnumerable nodes) { object container = null; foreach (TreeNode node in nodes) { DataNode dataNode = node.Tag as DataNode; if (container == null) container = dataNode.Parent; if (container != dataNode.Parent) return false; } return true; } private bool CommonType (IEnumerable nodes) { Type datatype = null; foreach (TreeNode node in nodes) { DataNode dataNode = node.Tag as DataNode; if (datatype == null) datatype = dataNode.GetType(); if (datatype != dataNode.GetType()) return false; } return true; } private bool SufficientCapabilities (IEnumerable nodes, GroupCapabilities commonCaps) { bool commonContainer = CommonContainer(nodes); bool commonType = CommonType(nodes); bool pass = true; if (commonContainer && commonType) pass &= ((commonCaps & GroupCapabilities.SiblingSameType) == GroupCapabilities.SiblingSameType); else if (commonContainer && !commonType) pass &= ((commonCaps & GroupCapabilities.SiblingMixedType) == GroupCapabilities.SiblingMixedType); else if (!commonContainer && commonType) pass &= ((commonCaps & GroupCapabilities.MultiSameType) == GroupCapabilities.MultiSameType); else if (!commonContainer && !commonType) pass &= ((commonCaps & GroupCapabilities.MultiMixedType) == GroupCapabilities.MultiMixedType); return pass; } #endregion } }