1 // ---------------------------------------------------------------------------------------------
2 #region // Copyright (c) 2004-2005, SIL International. All Rights Reserved.
3 // <copyright from='2004' to='2005' company='SIL International'>
4 // Copyright (c) 2004-2005, SIL International. All Rights Reserved.
6 // Distributable under the terms of either the Common Public License or the
7 // GNU Lesser General Public License, as specified in the LICENSING.txt file.
11 // File: TriStateTreeView.cs
12 // Responsibility: Eberhard Beilharz/Tim Steenwyk
16 // ---------------------------------------------------------------------------------------------
18 using System.Collections;
19 using System.ComponentModel;
22 using System.Runtime.InteropServices;
23 using System.Windows.Forms;
24 using Skybound.VisualStyles;
26 namespace SIL.FieldWorks.Common.Controls
28 /// ----------------------------------------------------------------------------------------
30 /// A tree view with tri-state check boxes
33 /// REVIEW: If we want to have icons in addition to the check boxes, we probably have to
34 /// set the icons for the check boxes in a different way. The windows tree view control
35 /// can have a separate image list for states.
37 /// ----------------------------------------------------------------------------------------
38 public class TriStateTreeView : TreeView
40 private System.Windows.Forms.ImageList m_TriStateImages;
41 private System.ComponentModel.IContainer components;
45 /// <remarks>The states corresponds to image index</remarks>
46 public enum CheckState
48 /// <summary>greyed out</summary>
50 /// <summary>Unchecked</summary>
52 /// <summary>Checked</summary>
56 #region Redefined Win-API structs and methods
57 /// <summary></summary>
58 [StructLayout(LayoutKind.Sequential, Pack=1)]
59 public struct TV_HITTESTINFO
61 /// <summary>Client coordinates of the point to test.</summary>
63 /// <summary>Variable that receives information about the results of a hit test.</summary>
65 /// <summary>Handle to the item that occupies the point.</summary>
69 /// <summary>Hit tests for tree view</summary>
73 /// <summary>In the client area, but below the last item.</summary>
75 /// <summary>On the bitmap associated with an item.</summary>
77 /// <summary>On the label (string) associated with an item.</summary>
79 /// <summary>In the indentation associated with an item.</summary>
80 OnItemIndent = 0x0008,
81 /// <summary>On the button associated with an item.</summary>
82 OnItemButton = 0x0010,
83 /// <summary>In the area to the right of an item. </summary>
85 /// <summary>On the state icon for a tree-view item that is in a user-defined state.</summary>
86 OnItemStateIcon = 0x0040,
87 /// <summary>On the bitmap or label associated with an item. </summary>
88 OnItem = (OnItemIcon | OnItemLabel | OnItemStateIcon),
89 /// <summary>Above the client area. </summary>
91 /// <summary>Below the client area.</summary>
93 /// <summary>To the right of the client area.</summary>
95 /// <summary>To the left of the client area.</summary>
99 /// <summary></summary>
100 public enum TreeViewMessages
102 /// <summary></summary>
103 TV_FIRST = 0x1100, // TreeView messages
104 /// <summary></summary>
105 TVM_HITTEST = (TV_FIRST + 17),
108 /// <summary></summary>
109 [DllImport("user32.dll", CharSet=CharSet.Auto)]
110 public static extern int SendMessage(IntPtr hWnd, TreeViewMessages msg, int wParam, ref TV_HITTESTINFO lParam);
113 #region Constructor and destructor
114 /// ------------------------------------------------------------------------------------
116 /// Initializes a new instance of the <see cref="TriStateTreeView"/> class.
118 /// ------------------------------------------------------------------------------------
119 public TriStateTreeView()
121 // This call is required by the Windows.Forms Form Designer.
122 InitializeComponent();
124 if (ThemeInformation.VisualStylesEnabled)
126 Bitmap bmp = new Bitmap(m_TriStateImages.ImageSize.Width, m_TriStateImages.ImageSize.Height);
127 Rectangle rc = new Rectangle(0, 0, bmp.Width, bmp.Height);
128 Graphics graphics = Graphics.FromImage(bmp);
130 ThemePaint.Draw(graphics, this, ThemeClasses.Button, ThemeParts.ButtonCheckBox,
131 ThemeStates.CheckBoxCheckedDisabled, rc, rc);
132 m_TriStateImages.Images[0] = bmp;
134 ThemePaint.Draw(graphics, this, ThemeClasses.Button, ThemeParts.ButtonCheckBox,
135 ThemeStates.CheckBoxUncheckedNormal, rc, rc);
136 m_TriStateImages.Images[1] = bmp;
138 ThemePaint.Draw(graphics, this, ThemeClasses.Button, ThemeParts.ButtonCheckBox,
139 ThemeStates.CheckBoxCheckedNormal, rc, rc);
140 m_TriStateImages.Images[2] = bmp;
143 ImageList = m_TriStateImages;
144 ImageIndex = (int)CheckState.Unchecked;
145 SelectedImageIndex = (int)CheckState.Unchecked;
148 /// -----------------------------------------------------------------------------------
150 /// Clean up any resources being used.
152 /// <param name="disposing"><c>true</c> to release both managed and unmanaged
153 /// resources; <c>false</c> to release only unmanaged resources.
155 /// -----------------------------------------------------------------------------------
156 protected override void Dispose( bool disposing )
160 if(components != null)
162 components.Dispose();
165 base.Dispose( disposing );
169 #region Component Designer generated code
170 /// -----------------------------------------------------------------------------------
172 /// Required method for Designer support - do not modify
173 /// the contents of this method with the code editor.
175 /// -----------------------------------------------------------------------------------
176 private void InitializeComponent()
178 this.components = new System.ComponentModel.Container();
179 System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(TriStateTreeView));
180 this.m_TriStateImages = new System.Windows.Forms.ImageList(this.components);
184 this.m_TriStateImages.ImageSize = new System.Drawing.Size(16, 16);
185 this.m_TriStateImages.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("m_TriStateImages.ImageStream")));
186 this.m_TriStateImages.TransparentColor = System.Drawing.Color.Magenta;
191 #region Hide no longer appropriate properties from Designer
192 /// ------------------------------------------------------------------------------------
196 /// ------------------------------------------------------------------------------------
198 public new bool CheckBoxes
200 get { return base.CheckBoxes; }
201 set { base.CheckBoxes = value; }
204 /// ------------------------------------------------------------------------------------
208 /// ------------------------------------------------------------------------------------
210 public new int ImageIndex
212 get { return base.ImageIndex; }
213 set { base.ImageIndex = value; }
216 /// ------------------------------------------------------------------------------------
220 /// ------------------------------------------------------------------------------------
222 public new ImageList ImageList
224 get { return base.ImageList; }
225 set { base.ImageList = value; }
228 /// ------------------------------------------------------------------------------------
232 /// ------------------------------------------------------------------------------------
234 public new int SelectedImageIndex
236 get { return base.SelectedImageIndex; }
237 set { base.SelectedImageIndex = value; }
242 /// ------------------------------------------------------------------------------------
244 /// Called when the user clicks on an item
246 /// <param name="e"></param>
247 /// ------------------------------------------------------------------------------------
248 protected override void OnClick(EventArgs e)
252 TV_HITTESTINFO hitTestInfo = new TV_HITTESTINFO();
253 hitTestInfo.pt = PointToClient(Control.MousePosition);
255 SendMessage(Handle, TreeViewMessages.TVM_HITTEST,
257 if ((hitTestInfo.flags & TVHit.OnItemIcon) == TVHit.OnItemIcon)
259 TreeNode node = GetNodeAt(hitTestInfo.pt);
261 ChangeNodeState(node);
265 /// ------------------------------------------------------------------------------------
267 /// Toggle item if user presses space bar
269 /// <param name="e"></param>
270 /// ------------------------------------------------------------------------------------
271 protected override void OnKeyDown(KeyEventArgs e)
275 if (e.KeyCode == Keys.Space)
276 ChangeNodeState(SelectedNode);
280 #region Private methods
281 /// ------------------------------------------------------------------------------------
283 /// Checks or unchecks all children
285 /// <param name="node"></param>
286 /// <param name="state"></param>
287 /// ------------------------------------------------------------------------------------
288 private void CheckNode(TreeNode node, CheckState state)
290 InternalSetChecked(node, state);
292 foreach (TreeNode child in node.Nodes)
293 CheckNode(child, state);
296 /// ------------------------------------------------------------------------------------
298 /// Called after a node changed its state. Has to go through all direct children and
299 /// set state based on children's state.
301 /// <param name="node">Parent node</param>
302 /// ------------------------------------------------------------------------------------
303 private void ChangeParent(TreeNode node)
308 CheckState state = GetChecked(node.FirstNode);
309 foreach (TreeNode child in node.Nodes)
310 state &= GetChecked(child);
312 if (InternalSetChecked(node, state))
313 ChangeParent(node.Parent);
316 /// ------------------------------------------------------------------------------------
318 /// Handles changing the state of a node
320 /// <param name="node"></param>
321 /// ------------------------------------------------------------------------------------
322 protected void ChangeNodeState(TreeNode node)
326 if (node.ImageIndex == (int)CheckState.Unchecked || node.ImageIndex < 0)
327 newState = CheckState.Checked;
329 newState = CheckState.Unchecked;
330 CheckNode(node, newState);
331 ChangeParent(node.Parent);
335 /// ------------------------------------------------------------------------------------
337 /// Sets the checked state of a node, but doesn't deal with children or parents
339 /// <param name="node">Node</param>
340 /// <param name="state">The new checked state</param>
341 /// <returns><c>true</c> if checked state was set to the requested state, otherwise
342 /// <c>false</c>.</returns>
343 /// ------------------------------------------------------------------------------------
344 private bool InternalSetChecked(TreeNode node, CheckState state)
346 TreeViewCancelEventArgs args =
347 new TreeViewCancelEventArgs(node, false, TreeViewAction.Unknown);
352 node.ImageIndex = (int)state;
353 node.SelectedImageIndex = (int)state;
355 OnAfterCheck(new TreeViewEventArgs(node, TreeViewAction.Unknown));
359 /// ------------------------------------------------------------------------------------
361 /// Build a list of all of the tag data for checked items in the tree.
363 /// <param name="node"></param>
364 /// <param name="list"></param>
365 /// ------------------------------------------------------------------------------------
366 private void BuildTagDataList(TreeNode node, ArrayList list)
368 if (GetChecked(node) == CheckState.Checked && node.Tag != null)
371 foreach (TreeNode child in node.Nodes)
372 BuildTagDataList(child, list);
375 /// ------------------------------------------------------------------------------------
377 /// Look through the tree nodes to find the node that has given tag data and check it.
379 /// <param name="node"></param>
380 /// <param name="tag"></param>
381 /// <param name="state"></param>
382 /// ------------------------------------------------------------------------------------
383 private void FindAndCheckNode(TreeNode node, object tag, CheckState state)
385 if (node.Tag != null && node.Tag.Equals(tag))
387 SetChecked(node, state);
391 foreach (TreeNode child in node.Nodes)
392 FindAndCheckNode(child, tag, state);
396 #region Public methods
397 /// ------------------------------------------------------------------------------------
399 /// Gets the checked state of a node
401 /// <param name="node">Node</param>
402 /// <returns>The checked state</returns>
403 /// ------------------------------------------------------------------------------------
404 public CheckState GetChecked(TreeNode node)
406 if (node.ImageIndex < 0)
407 return CheckState.Unchecked;
409 return (CheckState)node.ImageIndex;
412 /// ------------------------------------------------------------------------------------
414 /// Sets the checked state of a node
416 /// <param name="node">Node</param>
417 /// <param name="state">The new checked state</param>
418 /// ------------------------------------------------------------------------------------
419 public void SetChecked(TreeNode node, CheckState state)
421 if (!InternalSetChecked(node, state))
423 CheckNode(node, state);
424 ChangeParent(node.Parent);
427 /// ------------------------------------------------------------------------------------
429 /// Find a node in the tree that matches the given tag data and set its checked state
431 /// <param name="tag"></param>
432 /// <param name="state"></param>
433 /// ------------------------------------------------------------------------------------
434 public void CheckNodeByTag(object tag, CheckState state)
438 foreach (TreeNode node in Nodes)
439 FindAndCheckNode(node, tag, state);
442 /// ------------------------------------------------------------------------------------
444 /// Return a list of the tag data for all of the checked items in the tree
446 /// <returns></returns>
447 /// ------------------------------------------------------------------------------------
448 public ArrayList GetCheckedTagData()
450 ArrayList list = new ArrayList();
452 foreach (TreeNode node in Nodes)
453 BuildTagDataList(node, list);