using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace FastReport.Controls { /// /// TreeView control with multiselect support. /// /// /// This control is for internal use only. /// [ToolboxItem(false)] public class TreeViewMultiSelect : TreeView { List selectedNodes; bool cancelNextSelection = false; bool passSelection = false; bool NewSelection = false; /// /// Creates a new instance of the TreeViewMultiSelect control. /// public TreeViewMultiSelect() { selectedNodes = new List(); } /// /// Gets a copy of list of selected nodes. /// public List SelectedNodes { get { return new List(selectedNodes); } /*set { if (value == null) { unhighlightSelectedNodes(); selectedNodes.Clear(); } else { unhighlightSelectedNodes(); selectedNodes = value; highlightSelectedNodes(); } todo: update this.SelectedNode }*/ } #region Triggers /// protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); paintSelectedNodes(); } /// protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e); paintSelectedNodes(); } /// protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) { base.OnNodeMouseClick(e); bool control = (ModifierKeys == Keys.Control); bool shift = (ModifierKeys == Keys.Shift); if (control && SelectedNode == e.Node && selectedNodes.Contains(e.Node) && selectedNodes.Count > 1) { passSelection = true; SelectedNode = selectedNodes[selectedNodes.Count - 2]; passSelection = false; unpaintSelectedNodes(); selectedNodes.Remove(e.Node); paintSelectedNodes(); cancelNextSelection = true; NewSelection = true; } if (selectedNodes.Count > 1 && !control && !shift) { unpaintSelectedNodes(); selectedNodes.Clear(); selectedNodes.Add(e.Node); paintSelectedNodes(); } } /// protected override void OnBeforeSelect(TreeViewCancelEventArgs e) { base.OnBeforeSelect(e); if (passSelection) return; if (cancelNextSelection) { e.Cancel = true; cancelNextSelection = false; return; } bool control = (ModifierKeys == Keys.Control); if (control && selectedNodes.Contains(e.Node)) { e.Cancel = true; unpaintSelectedNodes(); selectedNodes.Remove(e.Node); paintSelectedNodes(); return; } } /// protected override void OnAfterSelect(TreeViewEventArgs e) { base.OnAfterSelect(e); if (passSelection) return; bool control = (ModifierKeys == Keys.Control); bool shift = (ModifierKeys == Keys.Shift); if (control && !shift) { if (selectedNodes.Contains(e.Node)) { unpaintSelectedNodes(); selectedNodes.Remove(e.Node); paintSelectedNodes(); } else { unpaintSelectedNodes(); SelectedNode = e.Node; NewSelection = true; selectedNodes.Add(e.Node); paintSelectedNodes(); } } else if (!control && shift) { if (selectedNodes.Count > 0 && isSameLevel(SelectedNode, e.Node)) { TreeNode SelectNode = NewSelection == true ? SelectedNodes[SelectedNodes.Count - 1] : SelectedNodes[0]; NewSelection = false; List nodes = getNodesOnSameLevel(SelectNode); int from = Math.Min(SelectNode.Index, e.Node.Index); int to = Math.Max(SelectNode.Index, e.Node.Index); bool needReverse = SelectNode.Index > e.Node.Index; unpaintSelectedNodes(); selectedNodes.Clear(); for (int i = from; i <= to && i < nodes.Count; i++) selectedNodes.Add(nodes[i]); if (needReverse) selectedNodes.Reverse(); paintSelectedNodes(); } } else { unpaintSelectedNodes(); selectedNodes.Clear(); selectedNodes.Add(e.Node); paintSelectedNodes(); } } #endregion #region Helpers bool isSameLevel(TreeNode node1, TreeNode node2) { TreeNode next = node1.NextNode; if (node1 == node2) { return true; } while (next != null) { if (next == node2) return true; next = next.NextNode; } TreeNode prev = node1.PrevNode; while (prev != null) { if (prev == node2) return true; prev = prev.PrevNode; } return false; } List getNodesOnSameLevel(TreeNode node) { List nodes = new List(); nodes.Add(node); TreeNode next = node.NextNode; while (next != null) { nodes.Add(next); next = next.NextNode; } TreeNode prev = node.PrevNode; while (prev != null) { nodes.Insert(0, prev); prev = prev.PrevNode; } return nodes; } void paintSelectedNodes() { Color backColor = Focused ? SystemColors.Highlight : SystemColors.Control; Color foreColor = Focused ? SystemColors.HighlightText : ForeColor; foreach (TreeNode node in selectedNodes) { node.BackColor = backColor; node.ForeColor = foreColor; } } void unpaintSelectedNodes() { foreach (TreeNode node in selectedNodes) { node.BackColor = BackColor; node.ForeColor = ForeColor; } } #endregion } }