moel@345
|
1 |
using System;
|
moel@345
|
2 |
using System.Collections.Generic;
|
moel@345
|
3 |
using System.Collections.ObjectModel;
|
moel@345
|
4 |
using System.ComponentModel;
|
moel@345
|
5 |
using System.Drawing;
|
moel@345
|
6 |
using System.Security.Permissions;
|
moel@345
|
7 |
using System.Threading;
|
moel@345
|
8 |
using System.Windows.Forms;
|
moel@345
|
9 |
using System.Collections;
|
moel@345
|
10 |
|
moel@345
|
11 |
using Aga.Controls.Tree.NodeControls;
|
moel@345
|
12 |
using Aga.Controls.Threading;
|
moel@345
|
13 |
|
moel@345
|
14 |
|
moel@345
|
15 |
namespace Aga.Controls.Tree
|
moel@345
|
16 |
{
|
moel@345
|
17 |
/// <summary>
|
moel@345
|
18 |
/// Extensible advanced <see cref="TreeView"/> implemented in 100% managed C# code.
|
moel@345
|
19 |
/// Features: Model/View architecture. Multiple column per node. Ability to select
|
moel@345
|
20 |
/// multiple tree nodes. Different types of controls for each node column:
|
moel@345
|
21 |
/// <see cref="CheckBox"/>, Icon, Label... Drag and Drop highlighting. Load on
|
moel@345
|
22 |
/// demand of nodes. Incremental search of nodes.
|
moel@345
|
23 |
/// </summary>
|
moel@345
|
24 |
public partial class TreeViewAdv : Control
|
moel@345
|
25 |
{
|
moel@345
|
26 |
private const int LeftMargin = 7;
|
moel@345
|
27 |
internal const int ItemDragSensivity = 4;
|
moel@345
|
28 |
private readonly int _columnHeaderHeight;
|
moel@345
|
29 |
private const int DividerWidth = 9;
|
moel@345
|
30 |
private const int DividerCorrectionGap = -2;
|
moel@345
|
31 |
|
moel@345
|
32 |
private Pen _linePen;
|
moel@345
|
33 |
private Pen _markPen;
|
moel@345
|
34 |
private bool _suspendUpdate;
|
moel@345
|
35 |
private bool _needFullUpdate;
|
moel@345
|
36 |
private bool _fireSelectionEvent;
|
moel@345
|
37 |
private NodePlusMinus _plusMinus;
|
moel@345
|
38 |
private ToolTip _toolTip;
|
moel@345
|
39 |
private DrawContext _measureContext;
|
moel@345
|
40 |
private TreeColumn _hotColumn;
|
moel@345
|
41 |
private IncrementalSearch _search;
|
moel@345
|
42 |
private List<TreeNodeAdv> _expandingNodes = new List<TreeNodeAdv>();
|
moel@345
|
43 |
private AbortableThreadPool _threadPool = new AbortableThreadPool();
|
moel@345
|
44 |
|
moel@345
|
45 |
#region Public Events
|
moel@345
|
46 |
|
moel@345
|
47 |
[Category("Action")]
|
moel@345
|
48 |
public event ItemDragEventHandler ItemDrag;
|
moel@345
|
49 |
private void OnItemDrag(MouseButtons buttons, object item)
|
moel@345
|
50 |
{
|
moel@345
|
51 |
if (ItemDrag != null)
|
moel@345
|
52 |
ItemDrag(this, new ItemDragEventArgs(buttons, item));
|
moel@345
|
53 |
}
|
moel@345
|
54 |
|
moel@345
|
55 |
[Category("Behavior")]
|
moel@345
|
56 |
public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseClick;
|
moel@345
|
57 |
private void OnNodeMouseClick(TreeNodeAdvMouseEventArgs args)
|
moel@345
|
58 |
{
|
moel@345
|
59 |
if (NodeMouseClick != null)
|
moel@345
|
60 |
NodeMouseClick(this, args);
|
moel@345
|
61 |
}
|
moel@345
|
62 |
|
moel@345
|
63 |
[Category("Behavior")]
|
moel@345
|
64 |
public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseDoubleClick;
|
moel@345
|
65 |
private void OnNodeMouseDoubleClick(TreeNodeAdvMouseEventArgs args)
|
moel@345
|
66 |
{
|
moel@345
|
67 |
if (NodeMouseDoubleClick != null)
|
moel@345
|
68 |
NodeMouseDoubleClick(this, args);
|
moel@345
|
69 |
}
|
moel@345
|
70 |
|
moel@345
|
71 |
[Category("Behavior")]
|
moel@345
|
72 |
public event EventHandler<TreeColumnEventArgs> ColumnWidthChanged;
|
moel@345
|
73 |
internal void OnColumnWidthChanged(TreeColumn column)
|
moel@345
|
74 |
{
|
moel@345
|
75 |
if (ColumnWidthChanged != null)
|
moel@345
|
76 |
ColumnWidthChanged(this, new TreeColumnEventArgs(column));
|
moel@345
|
77 |
}
|
moel@345
|
78 |
|
moel@345
|
79 |
[Category("Behavior")]
|
moel@345
|
80 |
public event EventHandler<TreeColumnEventArgs> ColumnReordered;
|
moel@345
|
81 |
internal void OnColumnReordered(TreeColumn column)
|
moel@345
|
82 |
{
|
moel@345
|
83 |
if (ColumnReordered != null)
|
moel@345
|
84 |
ColumnReordered(this, new TreeColumnEventArgs(column));
|
moel@345
|
85 |
}
|
moel@345
|
86 |
|
moel@345
|
87 |
[Category("Behavior")]
|
moel@345
|
88 |
public event EventHandler<TreeColumnEventArgs> ColumnClicked;
|
moel@345
|
89 |
internal void OnColumnClicked(TreeColumn column)
|
moel@345
|
90 |
{
|
moel@345
|
91 |
if (ColumnClicked != null)
|
moel@345
|
92 |
ColumnClicked(this, new TreeColumnEventArgs(column));
|
moel@345
|
93 |
}
|
moel@345
|
94 |
|
moel@345
|
95 |
[Category("Behavior")]
|
moel@345
|
96 |
public event EventHandler SelectionChanged;
|
moel@345
|
97 |
internal void OnSelectionChanged()
|
moel@345
|
98 |
{
|
moel@345
|
99 |
if (SuspendSelectionEvent)
|
moel@345
|
100 |
_fireSelectionEvent = true;
|
moel@345
|
101 |
else
|
moel@345
|
102 |
{
|
moel@345
|
103 |
_fireSelectionEvent = false;
|
moel@345
|
104 |
if (SelectionChanged != null)
|
moel@345
|
105 |
SelectionChanged(this, EventArgs.Empty);
|
moel@345
|
106 |
}
|
moel@345
|
107 |
}
|
moel@345
|
108 |
|
moel@345
|
109 |
[Category("Behavior")]
|
moel@345
|
110 |
public event EventHandler<TreeViewAdvEventArgs> Collapsing;
|
moel@345
|
111 |
private void OnCollapsing(TreeNodeAdv node)
|
moel@345
|
112 |
{
|
moel@345
|
113 |
if (Collapsing != null)
|
moel@345
|
114 |
Collapsing(this, new TreeViewAdvEventArgs(node));
|
moel@345
|
115 |
}
|
moel@345
|
116 |
|
moel@345
|
117 |
[Category("Behavior")]
|
moel@345
|
118 |
public event EventHandler<TreeViewAdvEventArgs> Collapsed;
|
moel@345
|
119 |
private void OnCollapsed(TreeNodeAdv node)
|
moel@345
|
120 |
{
|
moel@345
|
121 |
if (Collapsed != null)
|
moel@345
|
122 |
Collapsed(this, new TreeViewAdvEventArgs(node));
|
moel@345
|
123 |
}
|
moel@345
|
124 |
|
moel@345
|
125 |
[Category("Behavior")]
|
moel@345
|
126 |
public event EventHandler<TreeViewAdvEventArgs> Expanding;
|
moel@345
|
127 |
private void OnExpanding(TreeNodeAdv node)
|
moel@345
|
128 |
{
|
moel@345
|
129 |
if (Expanding != null)
|
moel@345
|
130 |
Expanding(this, new TreeViewAdvEventArgs(node));
|
moel@345
|
131 |
}
|
moel@345
|
132 |
|
moel@345
|
133 |
[Category("Behavior")]
|
moel@345
|
134 |
public event EventHandler<TreeViewAdvEventArgs> Expanded;
|
moel@345
|
135 |
private void OnExpanded(TreeNodeAdv node)
|
moel@345
|
136 |
{
|
moel@345
|
137 |
if (Expanded != null)
|
moel@345
|
138 |
Expanded(this, new TreeViewAdvEventArgs(node));
|
moel@345
|
139 |
}
|
moel@345
|
140 |
|
moel@345
|
141 |
[Category("Behavior")]
|
moel@345
|
142 |
public event EventHandler GridLineStyleChanged;
|
moel@345
|
143 |
private void OnGridLineStyleChanged()
|
moel@345
|
144 |
{
|
moel@345
|
145 |
if (GridLineStyleChanged != null)
|
moel@345
|
146 |
GridLineStyleChanged(this, EventArgs.Empty);
|
moel@345
|
147 |
}
|
moel@345
|
148 |
|
moel@345
|
149 |
[Category("Behavior")]
|
moel@345
|
150 |
public event ScrollEventHandler Scroll;
|
moel@345
|
151 |
protected virtual void OnScroll(ScrollEventArgs e)
|
moel@345
|
152 |
{
|
moel@345
|
153 |
if (Scroll != null)
|
moel@345
|
154 |
Scroll(this, e);
|
moel@345
|
155 |
}
|
moel@345
|
156 |
|
moel@345
|
157 |
[Category("Behavior")]
|
moel@345
|
158 |
public event EventHandler<TreeViewRowDrawEventArgs> RowDraw;
|
moel@345
|
159 |
protected virtual void OnRowDraw(PaintEventArgs e, TreeNodeAdv node, DrawContext context, int row, Rectangle rowRect)
|
moel@345
|
160 |
{
|
moel@345
|
161 |
if (RowDraw != null)
|
moel@345
|
162 |
{
|
moel@345
|
163 |
TreeViewRowDrawEventArgs args = new TreeViewRowDrawEventArgs(e.Graphics, e.ClipRectangle, node, context, row, rowRect);
|
moel@345
|
164 |
RowDraw(this, args);
|
moel@345
|
165 |
}
|
moel@345
|
166 |
}
|
moel@345
|
167 |
|
moel@345
|
168 |
/// <summary>
|
moel@345
|
169 |
/// Fires when control is going to draw. Can be used to change text or back color
|
moel@345
|
170 |
/// </summary>
|
moel@345
|
171 |
[Category("Behavior")]
|
moel@345
|
172 |
public event EventHandler<DrawEventArgs> DrawControl;
|
moel@345
|
173 |
|
moel@345
|
174 |
internal bool DrawControlMustBeFired()
|
moel@345
|
175 |
{
|
moel@345
|
176 |
return DrawControl != null;
|
moel@345
|
177 |
}
|
moel@345
|
178 |
|
moel@345
|
179 |
internal void FireDrawControl(DrawEventArgs args)
|
moel@345
|
180 |
{
|
moel@345
|
181 |
OnDrawControl(args);
|
moel@345
|
182 |
}
|
moel@345
|
183 |
|
moel@345
|
184 |
protected virtual void OnDrawControl(DrawEventArgs args)
|
moel@345
|
185 |
{
|
moel@345
|
186 |
if (DrawControl != null)
|
moel@345
|
187 |
DrawControl(this, args);
|
moel@345
|
188 |
}
|
moel@345
|
189 |
|
moel@345
|
190 |
|
moel@345
|
191 |
[Category("Drag Drop")]
|
moel@345
|
192 |
public event EventHandler<DropNodeValidatingEventArgs> DropNodeValidating;
|
moel@345
|
193 |
protected virtual void OnDropNodeValidating(Point point, ref TreeNodeAdv node)
|
moel@345
|
194 |
{
|
moel@345
|
195 |
if (DropNodeValidating != null)
|
moel@345
|
196 |
{
|
moel@345
|
197 |
DropNodeValidatingEventArgs args = new DropNodeValidatingEventArgs(point, node);
|
moel@345
|
198 |
DropNodeValidating(this, args);
|
moel@345
|
199 |
node = args.Node;
|
moel@345
|
200 |
}
|
moel@345
|
201 |
}
|
moel@345
|
202 |
#endregion
|
moel@345
|
203 |
|
moel@345
|
204 |
public TreeViewAdv()
|
moel@345
|
205 |
{
|
moel@345
|
206 |
InitializeComponent();
|
moel@345
|
207 |
SetStyle(ControlStyles.AllPaintingInWmPaint
|
moel@345
|
208 |
| ControlStyles.UserPaint
|
moel@345
|
209 |
| ControlStyles.OptimizedDoubleBuffer
|
moel@345
|
210 |
| ControlStyles.ResizeRedraw
|
moel@345
|
211 |
| ControlStyles.Selectable
|
moel@345
|
212 |
, true);
|
moel@345
|
213 |
|
moel@345
|
214 |
|
moel@345
|
215 |
if (Application.RenderWithVisualStyles)
|
moel@345
|
216 |
_columnHeaderHeight = 20;
|
moel@345
|
217 |
else
|
moel@345
|
218 |
_columnHeaderHeight = 17;
|
moel@345
|
219 |
|
moel@345
|
220 |
//BorderStyle = BorderStyle.Fixed3D;
|
moel@345
|
221 |
_hScrollBar.Height = SystemInformation.HorizontalScrollBarHeight;
|
moel@345
|
222 |
_vScrollBar.Width = SystemInformation.VerticalScrollBarWidth;
|
moel@345
|
223 |
_rowLayout = new FixedRowHeightLayout(this, RowHeight);
|
moel@345
|
224 |
_rowMap = new List<TreeNodeAdv>();
|
moel@345
|
225 |
_selection = new List<TreeNodeAdv>();
|
moel@345
|
226 |
_readonlySelection = new ReadOnlyCollection<TreeNodeAdv>(_selection);
|
moel@345
|
227 |
_columns = new TreeColumnCollection(this);
|
moel@345
|
228 |
_toolTip = new ToolTip();
|
moel@345
|
229 |
|
moel@345
|
230 |
_measureContext = new DrawContext();
|
moel@345
|
231 |
_measureContext.Font = Font;
|
moel@345
|
232 |
_measureContext.Graphics = Graphics.FromImage(new Bitmap(1, 1));
|
moel@345
|
233 |
|
moel@345
|
234 |
Input = new NormalInputState(this);
|
moel@345
|
235 |
_search = new IncrementalSearch(this);
|
moel@345
|
236 |
CreateNodes();
|
moel@345
|
237 |
CreatePens();
|
moel@345
|
238 |
|
moel@345
|
239 |
ArrangeControls();
|
moel@345
|
240 |
|
moel@345
|
241 |
_plusMinus = new NodePlusMinus();
|
moel@345
|
242 |
_controls = new NodeControlsCollection(this);
|
moel@345
|
243 |
|
moel@345
|
244 |
Font = _font;
|
moel@345
|
245 |
ExpandingIcon.IconChanged += ExpandingIconChanged;
|
moel@345
|
246 |
}
|
moel@345
|
247 |
|
moel@345
|
248 |
void ExpandingIconChanged(object sender, EventArgs e)
|
moel@345
|
249 |
{
|
moel@345
|
250 |
if (IsHandleCreated && !IsDisposed)
|
moel@345
|
251 |
BeginInvoke(new MethodInvoker(DrawIcons));
|
moel@345
|
252 |
}
|
moel@345
|
253 |
|
moel@345
|
254 |
private void DrawIcons()
|
moel@345
|
255 |
{
|
moel@345
|
256 |
using (Graphics gr = Graphics.FromHwnd(this.Handle))
|
moel@345
|
257 |
{
|
moel@345
|
258 |
//Apply the same Graphics Transform logic as used in OnPaint.
|
moel@345
|
259 |
int y = 0;
|
moel@345
|
260 |
if (UseColumns)
|
moel@345
|
261 |
{
|
moel@345
|
262 |
y += ColumnHeaderHeight;
|
moel@345
|
263 |
if (Columns.Count == 0)
|
moel@345
|
264 |
return;
|
moel@345
|
265 |
}
|
moel@345
|
266 |
int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y;
|
moel@345
|
267 |
y -= firstRowY;
|
moel@345
|
268 |
gr.ResetTransform();
|
moel@345
|
269 |
gr.TranslateTransform(-OffsetX, y);
|
moel@345
|
270 |
|
moel@345
|
271 |
DrawContext context = new DrawContext();
|
moel@345
|
272 |
context.Graphics = gr;
|
moel@345
|
273 |
for (int i = 0; i < _expandingNodes.Count; i++)
|
moel@345
|
274 |
{
|
moel@345
|
275 |
foreach (NodeControlInfo item in GetNodeControls(_expandingNodes[i]))
|
moel@345
|
276 |
{
|
moel@345
|
277 |
if (item.Control is ExpandingIcon)
|
moel@345
|
278 |
{
|
moel@345
|
279 |
Rectangle bounds = item.Bounds;
|
moel@345
|
280 |
if (item.Node.Parent == null && UseColumns)
|
moel@345
|
281 |
bounds.Location = Point.Empty; // display root expanding icon at 0,0
|
moel@345
|
282 |
|
moel@345
|
283 |
context.Bounds = bounds;
|
moel@345
|
284 |
item.Control.Draw(item.Node, context);
|
moel@345
|
285 |
}
|
moel@345
|
286 |
}
|
moel@345
|
287 |
}
|
moel@345
|
288 |
}
|
moel@345
|
289 |
}
|
moel@345
|
290 |
|
moel@345
|
291 |
#region Public Methods
|
moel@345
|
292 |
|
moel@345
|
293 |
public TreePath GetPath(TreeNodeAdv node)
|
moel@345
|
294 |
{
|
moel@345
|
295 |
if (node == _root)
|
moel@345
|
296 |
return TreePath.Empty;
|
moel@345
|
297 |
else
|
moel@345
|
298 |
{
|
moel@345
|
299 |
Stack<object> stack = new Stack<object>();
|
moel@345
|
300 |
while (node != _root && node != null)
|
moel@345
|
301 |
{
|
moel@345
|
302 |
stack.Push(node.Tag);
|
moel@345
|
303 |
node = node.Parent;
|
moel@345
|
304 |
}
|
moel@345
|
305 |
return new TreePath(stack.ToArray());
|
moel@345
|
306 |
}
|
moel@345
|
307 |
}
|
moel@345
|
308 |
|
moel@345
|
309 |
public TreeNodeAdv GetNodeAt(Point point)
|
moel@345
|
310 |
{
|
moel@345
|
311 |
NodeControlInfo info = GetNodeControlInfoAt(point);
|
moel@345
|
312 |
return info.Node;
|
moel@345
|
313 |
}
|
moel@345
|
314 |
|
moel@345
|
315 |
public NodeControlInfo GetNodeControlInfoAt(Point point)
|
moel@345
|
316 |
{
|
moel@345
|
317 |
if (point.X < 0 || point.Y < 0)
|
moel@345
|
318 |
return NodeControlInfo.Empty;
|
moel@345
|
319 |
|
moel@345
|
320 |
int row = _rowLayout.GetRowAt(point);
|
moel@345
|
321 |
if (row < RowCount && row >= 0)
|
moel@345
|
322 |
return GetNodeControlInfoAt(RowMap[row], point);
|
moel@345
|
323 |
else
|
moel@345
|
324 |
return NodeControlInfo.Empty;
|
moel@345
|
325 |
}
|
moel@345
|
326 |
|
moel@345
|
327 |
private NodeControlInfo GetNodeControlInfoAt(TreeNodeAdv node, Point point)
|
moel@345
|
328 |
{
|
moel@345
|
329 |
Rectangle rect = _rowLayout.GetRowBounds(FirstVisibleRow);
|
moel@345
|
330 |
point.Y += (rect.Y - ColumnHeaderHeight);
|
moel@345
|
331 |
point.X += OffsetX;
|
moel@345
|
332 |
foreach (NodeControlInfo info in GetNodeControls(node))
|
moel@345
|
333 |
if (info.Bounds.Contains(point))
|
moel@345
|
334 |
return info;
|
moel@345
|
335 |
|
moel@345
|
336 |
if (FullRowSelect)
|
moel@345
|
337 |
return new NodeControlInfo(null, Rectangle.Empty, node);
|
moel@345
|
338 |
else
|
moel@345
|
339 |
return NodeControlInfo.Empty;
|
moel@345
|
340 |
}
|
moel@345
|
341 |
|
moel@345
|
342 |
public void BeginUpdate()
|
moel@345
|
343 |
{
|
moel@345
|
344 |
_suspendUpdate = true;
|
moel@345
|
345 |
SuspendSelectionEvent = true;
|
moel@345
|
346 |
}
|
moel@345
|
347 |
|
moel@345
|
348 |
public void EndUpdate()
|
moel@345
|
349 |
{
|
moel@345
|
350 |
_suspendUpdate = false;
|
moel@345
|
351 |
if (_needFullUpdate)
|
moel@345
|
352 |
FullUpdate();
|
moel@345
|
353 |
else
|
moel@345
|
354 |
UpdateView();
|
moel@345
|
355 |
SuspendSelectionEvent = false;
|
moel@345
|
356 |
}
|
moel@345
|
357 |
|
moel@345
|
358 |
public void ExpandAll()
|
moel@345
|
359 |
{
|
moel@345
|
360 |
_root.ExpandAll();
|
moel@345
|
361 |
}
|
moel@345
|
362 |
|
moel@345
|
363 |
public void CollapseAll()
|
moel@345
|
364 |
{
|
moel@345
|
365 |
_root.CollapseAll();
|
moel@345
|
366 |
}
|
moel@345
|
367 |
|
moel@345
|
368 |
/// <summary>
|
moel@345
|
369 |
/// Expand all parent nodes, andd scroll to the specified node
|
moel@345
|
370 |
/// </summary>
|
moel@345
|
371 |
public void EnsureVisible(TreeNodeAdv node)
|
moel@345
|
372 |
{
|
moel@345
|
373 |
if (node == null)
|
moel@345
|
374 |
throw new ArgumentNullException("node");
|
moel@345
|
375 |
|
moel@345
|
376 |
if (!IsMyNode(node))
|
moel@345
|
377 |
throw new ArgumentException();
|
moel@345
|
378 |
|
moel@345
|
379 |
TreeNodeAdv parent = node.Parent;
|
moel@345
|
380 |
while (parent != _root)
|
moel@345
|
381 |
{
|
moel@345
|
382 |
parent.IsExpanded = true;
|
moel@345
|
383 |
parent = parent.Parent;
|
moel@345
|
384 |
}
|
moel@345
|
385 |
ScrollTo(node);
|
moel@345
|
386 |
}
|
moel@345
|
387 |
|
moel@345
|
388 |
/// <summary>
|
moel@345
|
389 |
/// Make node visible, scroll if needed. All parent nodes of the specified node must be expanded
|
moel@345
|
390 |
/// </summary>
|
moel@345
|
391 |
/// <param name="node"></param>
|
moel@345
|
392 |
public void ScrollTo(TreeNodeAdv node)
|
moel@345
|
393 |
{
|
moel@345
|
394 |
if (node == null)
|
moel@345
|
395 |
throw new ArgumentNullException("node");
|
moel@345
|
396 |
|
moel@345
|
397 |
if (!IsMyNode(node))
|
moel@345
|
398 |
throw new ArgumentException();
|
moel@345
|
399 |
|
moel@345
|
400 |
if (node.Row < 0)
|
moel@345
|
401 |
CreateRowMap();
|
moel@345
|
402 |
|
moel@345
|
403 |
int row = -1;
|
moel@345
|
404 |
|
moel@345
|
405 |
if (node.Row < FirstVisibleRow)
|
moel@345
|
406 |
row = node.Row;
|
moel@345
|
407 |
else
|
moel@345
|
408 |
{
|
moel@345
|
409 |
int pageStart = _rowLayout.GetRowBounds(FirstVisibleRow).Top;
|
moel@345
|
410 |
int rowBottom = _rowLayout.GetRowBounds(node.Row).Bottom;
|
moel@345
|
411 |
if (rowBottom > pageStart + DisplayRectangle.Height - ColumnHeaderHeight)
|
moel@345
|
412 |
row = _rowLayout.GetFirstRow(node.Row);
|
moel@345
|
413 |
}
|
moel@345
|
414 |
|
moel@345
|
415 |
if (row >= _vScrollBar.Minimum && row <= _vScrollBar.Maximum)
|
moel@345
|
416 |
_vScrollBar.Value = row;
|
moel@345
|
417 |
}
|
moel@345
|
418 |
|
moel@345
|
419 |
public void ClearSelection()
|
moel@345
|
420 |
{
|
moel@345
|
421 |
BeginUpdate();
|
moel@345
|
422 |
try
|
moel@345
|
423 |
{
|
moel@345
|
424 |
ClearSelectionInternal();
|
moel@345
|
425 |
}
|
moel@345
|
426 |
finally
|
moel@345
|
427 |
{
|
moel@345
|
428 |
EndUpdate();
|
moel@345
|
429 |
}
|
moel@345
|
430 |
}
|
moel@345
|
431 |
|
moel@345
|
432 |
internal void ClearSelectionInternal()
|
moel@345
|
433 |
{
|
moel@345
|
434 |
while (Selection.Count > 0)
|
moel@345
|
435 |
{
|
moel@345
|
436 |
var t = Selection[0];
|
moel@345
|
437 |
t.IsSelected = false;
|
moel@345
|
438 |
Selection.Remove(t); //hack
|
moel@345
|
439 |
}
|
moel@345
|
440 |
}
|
moel@345
|
441 |
|
moel@345
|
442 |
#endregion
|
moel@345
|
443 |
|
moel@345
|
444 |
protected override void OnSizeChanged(EventArgs e)
|
moel@345
|
445 |
{
|
moel@345
|
446 |
ArrangeControls();
|
moel@345
|
447 |
SafeUpdateScrollBars();
|
moel@345
|
448 |
base.OnSizeChanged(e);
|
moel@345
|
449 |
}
|
moel@345
|
450 |
|
moel@345
|
451 |
private void ArrangeControls()
|
moel@345
|
452 |
{
|
moel@345
|
453 |
int hBarSize = _hScrollBar.Height;
|
moel@345
|
454 |
int vBarSize = _vScrollBar.Width;
|
moel@345
|
455 |
Rectangle clientRect = ClientRectangle;
|
moel@345
|
456 |
|
moel@345
|
457 |
_hScrollBar.SetBounds(clientRect.X, clientRect.Bottom - hBarSize,
|
moel@345
|
458 |
clientRect.Width - vBarSize, hBarSize);
|
moel@345
|
459 |
|
moel@345
|
460 |
_vScrollBar.SetBounds(clientRect.Right - vBarSize, clientRect.Y,
|
moel@345
|
461 |
vBarSize, clientRect.Height - hBarSize);
|
moel@345
|
462 |
}
|
moel@345
|
463 |
|
moel@345
|
464 |
private void SafeUpdateScrollBars()
|
moel@345
|
465 |
{
|
moel@345
|
466 |
if (InvokeRequired)
|
moel@345
|
467 |
BeginInvoke(new MethodInvoker(UpdateScrollBars));
|
moel@345
|
468 |
else
|
moel@345
|
469 |
UpdateScrollBars();
|
moel@345
|
470 |
}
|
moel@345
|
471 |
|
moel@345
|
472 |
private void UpdateScrollBars()
|
moel@345
|
473 |
{
|
moel@345
|
474 |
UpdateVScrollBar();
|
moel@345
|
475 |
UpdateHScrollBar();
|
moel@345
|
476 |
UpdateVScrollBar();
|
moel@345
|
477 |
UpdateHScrollBar();
|
moel@345
|
478 |
_hScrollBar.Width = DisplayRectangle.Width;
|
moel@345
|
479 |
_vScrollBar.Height = DisplayRectangle.Height;
|
moel@345
|
480 |
}
|
moel@345
|
481 |
|
moel@345
|
482 |
private void UpdateHScrollBar()
|
moel@345
|
483 |
{
|
moel@345
|
484 |
_hScrollBar.Maximum = ContentWidth;
|
moel@345
|
485 |
_hScrollBar.LargeChange = Math.Max(DisplayRectangle.Width, 0);
|
moel@345
|
486 |
_hScrollBar.SmallChange = 5;
|
moel@345
|
487 |
_hScrollBar.Visible = _hScrollBar.LargeChange < _hScrollBar.Maximum;
|
moel@345
|
488 |
_hScrollBar.Value = Math.Min(_hScrollBar.Value, _hScrollBar.Maximum - _hScrollBar.LargeChange + 1);
|
moel@345
|
489 |
}
|
moel@345
|
490 |
|
moel@345
|
491 |
private void UpdateVScrollBar()
|
moel@345
|
492 |
{
|
moel@345
|
493 |
_vScrollBar.Maximum = Math.Max(RowCount - 1, 0);
|
moel@345
|
494 |
_vScrollBar.LargeChange = _rowLayout.PageRowCount;
|
moel@345
|
495 |
_vScrollBar.Visible = (RowCount > 0) && (_vScrollBar.LargeChange <= _vScrollBar.Maximum);
|
moel@345
|
496 |
_vScrollBar.Value = Math.Min(_vScrollBar.Value, _vScrollBar.Maximum - _vScrollBar.LargeChange + 1);
|
moel@345
|
497 |
}
|
moel@345
|
498 |
|
moel@345
|
499 |
protected override CreateParams CreateParams
|
moel@345
|
500 |
{
|
moel@345
|
501 |
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
moel@345
|
502 |
get
|
moel@345
|
503 |
{
|
moel@345
|
504 |
CreateParams res = base.CreateParams;
|
moel@345
|
505 |
switch (BorderStyle)
|
moel@345
|
506 |
{
|
moel@345
|
507 |
case BorderStyle.FixedSingle:
|
moel@345
|
508 |
res.Style |= 0x800000;
|
moel@345
|
509 |
break;
|
moel@345
|
510 |
case BorderStyle.Fixed3D:
|
moel@345
|
511 |
res.ExStyle |= 0x200;
|
moel@345
|
512 |
break;
|
moel@345
|
513 |
}
|
moel@345
|
514 |
return res;
|
moel@345
|
515 |
}
|
moel@345
|
516 |
}
|
moel@345
|
517 |
|
moel@345
|
518 |
protected override void OnGotFocus(EventArgs e)
|
moel@345
|
519 |
{
|
moel@345
|
520 |
UpdateView();
|
moel@345
|
521 |
ChangeInput();
|
moel@345
|
522 |
base.OnGotFocus(e);
|
moel@345
|
523 |
}
|
moel@345
|
524 |
|
moel@345
|
525 |
protected override void OnFontChanged(EventArgs e)
|
moel@345
|
526 |
{
|
moel@345
|
527 |
base.OnFontChanged(e);
|
moel@345
|
528 |
_measureContext.Font = Font;
|
moel@345
|
529 |
FullUpdate();
|
moel@345
|
530 |
}
|
moel@345
|
531 |
|
moel@345
|
532 |
internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node)
|
moel@345
|
533 |
{
|
moel@345
|
534 |
if (node == null)
|
moel@345
|
535 |
yield break;
|
moel@345
|
536 |
Rectangle rowRect = _rowLayout.GetRowBounds(node.Row);
|
moel@345
|
537 |
foreach (NodeControlInfo n in GetNodeControls(node, rowRect))
|
moel@345
|
538 |
yield return n;
|
moel@345
|
539 |
}
|
moel@345
|
540 |
|
moel@345
|
541 |
internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node, Rectangle rowRect)
|
moel@345
|
542 |
{
|
moel@345
|
543 |
if (node == null)
|
moel@345
|
544 |
yield break;
|
moel@345
|
545 |
|
moel@345
|
546 |
int y = rowRect.Y;
|
moel@345
|
547 |
int x = (node.Level - 1) * _indent + LeftMargin;
|
moel@345
|
548 |
int width = 0;
|
moel@345
|
549 |
if (node.Row == 0 && ShiftFirstNode)
|
moel@345
|
550 |
x -= _indent;
|
moel@345
|
551 |
Rectangle rect = Rectangle.Empty;
|
moel@345
|
552 |
|
moel@345
|
553 |
if (ShowPlusMinus)
|
moel@345
|
554 |
{
|
moel@345
|
555 |
width = _plusMinus.GetActualSize(node, _measureContext).Width;
|
moel@345
|
556 |
rect = new Rectangle(x, y, width, rowRect.Height);
|
moel@345
|
557 |
if (UseColumns && Columns.Count > 0 && Columns[0].Width < rect.Right)
|
moel@345
|
558 |
rect.Width = Columns[0].Width - x;
|
moel@345
|
559 |
|
moel@345
|
560 |
yield return new NodeControlInfo(_plusMinus, rect, node);
|
moel@345
|
561 |
x += width;
|
moel@345
|
562 |
}
|
moel@345
|
563 |
|
moel@345
|
564 |
if (!UseColumns)
|
moel@345
|
565 |
{
|
moel@345
|
566 |
foreach (NodeControl c in NodeControls)
|
moel@345
|
567 |
{
|
moel@345
|
568 |
Size s = c.GetActualSize(node, _measureContext);
|
moel@345
|
569 |
if (!s.IsEmpty)
|
moel@345
|
570 |
{
|
moel@345
|
571 |
width = s.Width;
|
moel@345
|
572 |
rect = new Rectangle(x, y, width, rowRect.Height);
|
moel@345
|
573 |
x += rect.Width;
|
moel@345
|
574 |
yield return new NodeControlInfo(c, rect, node);
|
moel@345
|
575 |
}
|
moel@345
|
576 |
}
|
moel@345
|
577 |
}
|
moel@345
|
578 |
else
|
moel@345
|
579 |
{
|
moel@345
|
580 |
int right = 0;
|
moel@345
|
581 |
foreach (TreeColumn col in Columns)
|
moel@345
|
582 |
{
|
moel@345
|
583 |
if (col.IsVisible && col.Width > 0)
|
moel@345
|
584 |
{
|
moel@345
|
585 |
right += col.Width;
|
moel@345
|
586 |
for (int i = 0; i < NodeControls.Count; i++)
|
moel@345
|
587 |
{
|
moel@345
|
588 |
NodeControl nc = NodeControls[i];
|
moel@345
|
589 |
if (nc.ParentColumn == col)
|
moel@345
|
590 |
{
|
moel@345
|
591 |
Size s = nc.GetActualSize(node, _measureContext);
|
moel@345
|
592 |
if (!s.IsEmpty)
|
moel@345
|
593 |
{
|
moel@345
|
594 |
bool isLastControl = true;
|
moel@345
|
595 |
for (int k = i + 1; k < NodeControls.Count; k++)
|
moel@345
|
596 |
if (NodeControls[k].ParentColumn == col)
|
moel@345
|
597 |
{
|
moel@345
|
598 |
isLastControl = false;
|
moel@345
|
599 |
break;
|
moel@345
|
600 |
}
|
moel@345
|
601 |
|
moel@345
|
602 |
width = right - x;
|
moel@345
|
603 |
if (!isLastControl)
|
moel@345
|
604 |
width = s.Width;
|
moel@345
|
605 |
int maxWidth = Math.Max(0, right - x);
|
moel@345
|
606 |
rect = new Rectangle(x, y, Math.Min(maxWidth, width), rowRect.Height);
|
moel@345
|
607 |
x += width;
|
moel@345
|
608 |
yield return new NodeControlInfo(nc, rect, node);
|
moel@345
|
609 |
}
|
moel@345
|
610 |
}
|
moel@345
|
611 |
}
|
moel@345
|
612 |
x = right;
|
moel@345
|
613 |
}
|
moel@345
|
614 |
}
|
moel@345
|
615 |
}
|
moel@345
|
616 |
}
|
moel@345
|
617 |
|
moel@345
|
618 |
internal static double Dist(Point p1, Point p2)
|
moel@345
|
619 |
{
|
moel@345
|
620 |
return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
|
moel@345
|
621 |
}
|
moel@345
|
622 |
|
moel@345
|
623 |
public void FullUpdate()
|
moel@345
|
624 |
{
|
moel@345
|
625 |
HideEditor();
|
moel@345
|
626 |
if (InvokeRequired)
|
moel@345
|
627 |
BeginInvoke(new MethodInvoker(UnsafeFullUpdate));
|
moel@345
|
628 |
else
|
moel@345
|
629 |
UnsafeFullUpdate();
|
moel@345
|
630 |
}
|
moel@345
|
631 |
|
moel@345
|
632 |
private void UnsafeFullUpdate()
|
moel@345
|
633 |
{
|
moel@345
|
634 |
_rowLayout.ClearCache();
|
moel@345
|
635 |
CreateRowMap();
|
moel@345
|
636 |
SafeUpdateScrollBars();
|
moel@345
|
637 |
UpdateView();
|
moel@345
|
638 |
_needFullUpdate = false;
|
moel@345
|
639 |
}
|
moel@345
|
640 |
|
moel@345
|
641 |
internal void UpdateView()
|
moel@345
|
642 |
{
|
moel@345
|
643 |
if (!_suspendUpdate)
|
moel@345
|
644 |
Invalidate(false);
|
moel@345
|
645 |
}
|
moel@345
|
646 |
|
moel@345
|
647 |
internal void UpdateHeaders()
|
moel@345
|
648 |
{
|
moel@345
|
649 |
Invalidate(new Rectangle(0, 0, Width, ColumnHeaderHeight));
|
moel@345
|
650 |
}
|
moel@345
|
651 |
|
moel@345
|
652 |
internal void UpdateColumns()
|
moel@345
|
653 |
{
|
moel@345
|
654 |
FullUpdate();
|
moel@345
|
655 |
}
|
moel@345
|
656 |
|
moel@345
|
657 |
private void CreateNodes()
|
moel@345
|
658 |
{
|
moel@345
|
659 |
Selection.Clear();
|
moel@345
|
660 |
SelectionStart = null;
|
moel@345
|
661 |
_root = new TreeNodeAdv(this, null);
|
moel@345
|
662 |
_root.IsExpanded = true;
|
moel@345
|
663 |
if (_root.Nodes.Count > 0)
|
moel@345
|
664 |
CurrentNode = _root.Nodes[0];
|
moel@345
|
665 |
else
|
moel@345
|
666 |
CurrentNode = null;
|
moel@345
|
667 |
}
|
moel@345
|
668 |
|
moel@345
|
669 |
internal void ReadChilds(TreeNodeAdv parentNode)
|
moel@345
|
670 |
{
|
moel@345
|
671 |
ReadChilds(parentNode, false);
|
moel@345
|
672 |
}
|
moel@345
|
673 |
|
moel@345
|
674 |
internal void ReadChilds(TreeNodeAdv parentNode, bool performFullUpdate)
|
moel@345
|
675 |
{
|
moel@345
|
676 |
if (!parentNode.IsLeaf)
|
moel@345
|
677 |
{
|
moel@345
|
678 |
parentNode.IsExpandedOnce = true;
|
moel@345
|
679 |
parentNode.Nodes.Clear();
|
moel@345
|
680 |
|
moel@345
|
681 |
if (Model != null)
|
moel@345
|
682 |
{
|
moel@345
|
683 |
IEnumerable items = Model.GetChildren(GetPath(parentNode));
|
moel@345
|
684 |
if (items != null)
|
moel@345
|
685 |
foreach (object obj in items)
|
moel@345
|
686 |
{
|
moel@345
|
687 |
AddNewNode(parentNode, obj, -1);
|
moel@345
|
688 |
if (performFullUpdate)
|
moel@345
|
689 |
FullUpdate();
|
moel@345
|
690 |
}
|
moel@345
|
691 |
}
|
moel@345
|
692 |
|
moel@345
|
693 |
if (parentNode.AutoExpandOnStructureChanged)
|
moel@345
|
694 |
parentNode.ExpandAll();
|
moel@345
|
695 |
}
|
moel@345
|
696 |
}
|
moel@345
|
697 |
|
moel@345
|
698 |
private void AddNewNode(TreeNodeAdv parent, object tag, int index)
|
moel@345
|
699 |
{
|
moel@345
|
700 |
TreeNodeAdv node = new TreeNodeAdv(this, tag);
|
moel@345
|
701 |
AddNode(parent, index, node);
|
moel@345
|
702 |
}
|
moel@345
|
703 |
|
moel@345
|
704 |
private void AddNode(TreeNodeAdv parent, int index, TreeNodeAdv node)
|
moel@345
|
705 |
{
|
moel@345
|
706 |
if (index >= 0 && index < parent.Nodes.Count)
|
moel@345
|
707 |
parent.Nodes.Insert(index, node);
|
moel@345
|
708 |
else
|
moel@345
|
709 |
parent.Nodes.Add(node);
|
moel@345
|
710 |
|
moel@345
|
711 |
node.IsLeaf = Model.IsLeaf(GetPath(node));
|
moel@345
|
712 |
if (node.IsLeaf)
|
moel@345
|
713 |
node.Nodes.Clear();
|
moel@345
|
714 |
if (!LoadOnDemand || node.IsExpandedOnce)
|
moel@345
|
715 |
ReadChilds(node);
|
moel@345
|
716 |
}
|
moel@345
|
717 |
|
moel@345
|
718 |
private struct ExpandArgs
|
moel@345
|
719 |
{
|
moel@345
|
720 |
public TreeNodeAdv Node;
|
moel@345
|
721 |
public bool Value;
|
moel@345
|
722 |
public bool IgnoreChildren;
|
moel@345
|
723 |
}
|
moel@345
|
724 |
|
moel@345
|
725 |
public void AbortBackgroundExpandingThreads()
|
moel@345
|
726 |
{
|
moel@345
|
727 |
_threadPool.CancelAll(true);
|
moel@345
|
728 |
for (int i = 0; i < _expandingNodes.Count; i++)
|
moel@345
|
729 |
_expandingNodes[i].IsExpandingNow = false;
|
moel@345
|
730 |
_expandingNodes.Clear();
|
moel@345
|
731 |
Invalidate();
|
moel@345
|
732 |
}
|
moel@345
|
733 |
|
moel@345
|
734 |
internal void SetIsExpanded(TreeNodeAdv node, bool value, bool ignoreChildren)
|
moel@345
|
735 |
{
|
moel@345
|
736 |
ExpandArgs eargs = new ExpandArgs();
|
moel@345
|
737 |
eargs.Node = node;
|
moel@345
|
738 |
eargs.Value = value;
|
moel@345
|
739 |
eargs.IgnoreChildren = ignoreChildren;
|
moel@345
|
740 |
|
moel@345
|
741 |
if (AsyncExpanding && LoadOnDemand && !_threadPool.IsMyThread(Thread.CurrentThread))
|
moel@345
|
742 |
{
|
moel@345
|
743 |
WaitCallback wc = delegate(object argument) { SetIsExpanded((ExpandArgs)argument); };
|
moel@345
|
744 |
_threadPool.QueueUserWorkItem(wc, eargs);
|
moel@345
|
745 |
}
|
moel@345
|
746 |
else
|
moel@345
|
747 |
SetIsExpanded(eargs);
|
moel@345
|
748 |
}
|
moel@345
|
749 |
|
moel@345
|
750 |
private void SetIsExpanded(ExpandArgs eargs)
|
moel@345
|
751 |
{
|
moel@345
|
752 |
bool update = !eargs.IgnoreChildren && !AsyncExpanding;
|
moel@345
|
753 |
if (update)
|
moel@345
|
754 |
BeginUpdate();
|
moel@345
|
755 |
try
|
moel@345
|
756 |
{
|
moel@345
|
757 |
if (IsMyNode(eargs.Node) && eargs.Node.IsExpanded != eargs.Value)
|
moel@345
|
758 |
SetIsExpanded(eargs.Node, eargs.Value);
|
moel@345
|
759 |
|
moel@345
|
760 |
if (!eargs.IgnoreChildren)
|
moel@345
|
761 |
SetIsExpandedRecursive(eargs.Node, eargs.Value);
|
moel@345
|
762 |
}
|
moel@345
|
763 |
finally
|
moel@345
|
764 |
{
|
moel@345
|
765 |
if (update)
|
moel@345
|
766 |
EndUpdate();
|
moel@345
|
767 |
}
|
moel@345
|
768 |
}
|
moel@345
|
769 |
|
moel@345
|
770 |
internal void SetIsExpanded(TreeNodeAdv node, bool value)
|
moel@345
|
771 |
{
|
moel@345
|
772 |
if (Root == node && !value)
|
moel@345
|
773 |
return; //Can't collapse root node
|
moel@345
|
774 |
|
moel@345
|
775 |
if (value)
|
moel@345
|
776 |
{
|
moel@345
|
777 |
OnExpanding(node);
|
moel@345
|
778 |
node.OnExpanding();
|
moel@345
|
779 |
}
|
moel@345
|
780 |
else
|
moel@345
|
781 |
{
|
moel@345
|
782 |
OnCollapsing(node);
|
moel@345
|
783 |
node.OnCollapsing();
|
moel@345
|
784 |
}
|
moel@345
|
785 |
|
moel@345
|
786 |
if (value && !node.IsExpandedOnce)
|
moel@345
|
787 |
{
|
moel@345
|
788 |
if (AsyncExpanding && LoadOnDemand)
|
moel@345
|
789 |
{
|
moel@345
|
790 |
AddExpandingNode(node);
|
moel@345
|
791 |
node.AssignIsExpanded(true);
|
moel@345
|
792 |
Invalidate();
|
moel@345
|
793 |
}
|
moel@345
|
794 |
ReadChilds(node, AsyncExpanding);
|
moel@345
|
795 |
RemoveExpandingNode(node);
|
moel@345
|
796 |
}
|
moel@345
|
797 |
node.AssignIsExpanded(value);
|
moel@345
|
798 |
SmartFullUpdate();
|
moel@345
|
799 |
|
moel@345
|
800 |
if (value)
|
moel@345
|
801 |
{
|
moel@345
|
802 |
OnExpanded(node);
|
moel@345
|
803 |
node.OnExpanded();
|
moel@345
|
804 |
}
|
moel@345
|
805 |
else
|
moel@345
|
806 |
{
|
moel@345
|
807 |
OnCollapsed(node);
|
moel@345
|
808 |
node.OnCollapsed();
|
moel@345
|
809 |
}
|
moel@345
|
810 |
}
|
moel@345
|
811 |
|
moel@345
|
812 |
private void RemoveExpandingNode(TreeNodeAdv node)
|
moel@345
|
813 |
{
|
moel@345
|
814 |
node.IsExpandingNow = false;
|
moel@345
|
815 |
_expandingNodes.Remove(node);
|
moel@345
|
816 |
if (_expandingNodes.Count <= 0)
|
moel@345
|
817 |
ExpandingIcon.Stop();
|
moel@345
|
818 |
}
|
moel@345
|
819 |
|
moel@345
|
820 |
private void AddExpandingNode(TreeNodeAdv node)
|
moel@345
|
821 |
{
|
moel@345
|
822 |
node.IsExpandingNow = true;
|
moel@345
|
823 |
_expandingNodes.Add(node);
|
moel@345
|
824 |
ExpandingIcon.Start();
|
moel@345
|
825 |
}
|
moel@345
|
826 |
|
moel@345
|
827 |
internal void SetIsExpandedRecursive(TreeNodeAdv root, bool value)
|
moel@345
|
828 |
{
|
moel@345
|
829 |
for (int i = 0; i < root.Nodes.Count; i++)
|
moel@345
|
830 |
{
|
moel@345
|
831 |
TreeNodeAdv node = root.Nodes[i];
|
moel@345
|
832 |
node.IsExpanded = value;
|
moel@345
|
833 |
SetIsExpandedRecursive(node, value);
|
moel@345
|
834 |
}
|
moel@345
|
835 |
}
|
moel@345
|
836 |
|
moel@345
|
837 |
private void CreateRowMap()
|
moel@345
|
838 |
{
|
moel@345
|
839 |
RowMap.Clear();
|
moel@345
|
840 |
int row = 0;
|
moel@345
|
841 |
_contentWidth = 0;
|
moel@345
|
842 |
foreach (TreeNodeAdv node in VisibleNodes)
|
moel@345
|
843 |
{
|
moel@345
|
844 |
node.Row = row;
|
moel@345
|
845 |
RowMap.Add(node);
|
moel@345
|
846 |
if (!UseColumns)
|
moel@345
|
847 |
{
|
moel@345
|
848 |
_contentWidth = Math.Max(_contentWidth, GetNodeWidth(node));
|
moel@345
|
849 |
}
|
moel@345
|
850 |
row++;
|
moel@345
|
851 |
}
|
moel@345
|
852 |
if (UseColumns)
|
moel@345
|
853 |
{
|
moel@345
|
854 |
_contentWidth = 0;
|
moel@345
|
855 |
foreach (TreeColumn col in _columns)
|
moel@345
|
856 |
if (col.IsVisible)
|
moel@345
|
857 |
_contentWidth += col.Width;
|
moel@345
|
858 |
}
|
moel@345
|
859 |
}
|
moel@345
|
860 |
|
moel@345
|
861 |
private int GetNodeWidth(TreeNodeAdv node)
|
moel@345
|
862 |
{
|
moel@345
|
863 |
if (node.RightBounds == null)
|
moel@345
|
864 |
{
|
moel@345
|
865 |
Rectangle res = GetNodeBounds(GetNodeControls(node, Rectangle.Empty));
|
moel@345
|
866 |
node.RightBounds = res.Right;
|
moel@345
|
867 |
}
|
moel@345
|
868 |
return node.RightBounds.Value;
|
moel@345
|
869 |
}
|
moel@345
|
870 |
|
moel@345
|
871 |
internal Rectangle GetNodeBounds(TreeNodeAdv node)
|
moel@345
|
872 |
{
|
moel@345
|
873 |
return GetNodeBounds(GetNodeControls(node));
|
moel@345
|
874 |
}
|
moel@345
|
875 |
|
moel@345
|
876 |
private Rectangle GetNodeBounds(IEnumerable<NodeControlInfo> nodeControls)
|
moel@345
|
877 |
{
|
moel@345
|
878 |
Rectangle res = Rectangle.Empty;
|
moel@345
|
879 |
foreach (NodeControlInfo info in nodeControls)
|
moel@345
|
880 |
{
|
moel@345
|
881 |
if (res == Rectangle.Empty)
|
moel@345
|
882 |
res = info.Bounds;
|
moel@345
|
883 |
else
|
moel@345
|
884 |
res = Rectangle.Union(res, info.Bounds);
|
moel@345
|
885 |
}
|
moel@345
|
886 |
return res;
|
moel@345
|
887 |
}
|
moel@345
|
888 |
|
moel@345
|
889 |
private void _vScrollBar_ValueChanged(object sender, EventArgs e)
|
moel@345
|
890 |
{
|
moel@345
|
891 |
FirstVisibleRow = _vScrollBar.Value;
|
moel@345
|
892 |
}
|
moel@345
|
893 |
|
moel@345
|
894 |
private void _hScrollBar_ValueChanged(object sender, EventArgs e)
|
moel@345
|
895 |
{
|
moel@345
|
896 |
OffsetX = _hScrollBar.Value;
|
moel@345
|
897 |
}
|
moel@345
|
898 |
|
moel@345
|
899 |
private void _vScrollBar_Scroll(object sender, ScrollEventArgs e)
|
moel@345
|
900 |
{
|
moel@345
|
901 |
OnScroll(e);
|
moel@345
|
902 |
}
|
moel@345
|
903 |
|
moel@345
|
904 |
private void _hScrollBar_Scroll(object sender, ScrollEventArgs e)
|
moel@345
|
905 |
{
|
moel@345
|
906 |
OnScroll(e);
|
moel@345
|
907 |
}
|
moel@345
|
908 |
|
moel@345
|
909 |
internal void SmartFullUpdate()
|
moel@345
|
910 |
{
|
moel@345
|
911 |
if (_suspendUpdate)
|
moel@345
|
912 |
_needFullUpdate = true;
|
moel@345
|
913 |
else
|
moel@345
|
914 |
FullUpdate();
|
moel@345
|
915 |
}
|
moel@345
|
916 |
|
moel@345
|
917 |
internal bool IsMyNode(TreeNodeAdv node)
|
moel@345
|
918 |
{
|
moel@345
|
919 |
if (node == null)
|
moel@345
|
920 |
return false;
|
moel@345
|
921 |
|
moel@345
|
922 |
if (node.Tree != this)
|
moel@345
|
923 |
return false;
|
moel@345
|
924 |
|
moel@345
|
925 |
while (node.Parent != null)
|
moel@345
|
926 |
node = node.Parent;
|
moel@345
|
927 |
|
moel@345
|
928 |
return node == _root;
|
moel@345
|
929 |
}
|
moel@345
|
930 |
|
moel@345
|
931 |
internal void UpdateSelection()
|
moel@345
|
932 |
{
|
moel@345
|
933 |
bool flag = false;
|
moel@345
|
934 |
|
moel@345
|
935 |
if (!IsMyNode(CurrentNode))
|
moel@345
|
936 |
CurrentNode = null;
|
moel@345
|
937 |
if (!IsMyNode(_selectionStart))
|
moel@345
|
938 |
_selectionStart = null;
|
moel@345
|
939 |
|
moel@345
|
940 |
for (int i = Selection.Count - 1; i >= 0; i--)
|
moel@345
|
941 |
if (!IsMyNode(Selection[i]))
|
moel@345
|
942 |
{
|
moel@345
|
943 |
flag = true;
|
moel@345
|
944 |
Selection.RemoveAt(i);
|
moel@345
|
945 |
}
|
moel@345
|
946 |
|
moel@345
|
947 |
if (flag)
|
moel@345
|
948 |
OnSelectionChanged();
|
moel@345
|
949 |
}
|
moel@345
|
950 |
|
moel@345
|
951 |
internal void ChangeColumnWidth(TreeColumn column)
|
moel@345
|
952 |
{
|
moel@345
|
953 |
if (!(_input is ResizeColumnState))
|
moel@345
|
954 |
{
|
moel@345
|
955 |
FullUpdate();
|
moel@345
|
956 |
OnColumnWidthChanged(column);
|
moel@345
|
957 |
}
|
moel@345
|
958 |
}
|
moel@345
|
959 |
|
moel@345
|
960 |
public TreeNodeAdv FindNode(TreePath path)
|
moel@345
|
961 |
{
|
moel@345
|
962 |
return FindNode(path, false);
|
moel@345
|
963 |
}
|
moel@345
|
964 |
|
moel@345
|
965 |
public TreeNodeAdv FindNode(TreePath path, bool readChilds)
|
moel@345
|
966 |
{
|
moel@345
|
967 |
if (path.IsEmpty())
|
moel@345
|
968 |
return _root;
|
moel@345
|
969 |
else
|
moel@345
|
970 |
return FindNode(_root, path, 0, readChilds);
|
moel@345
|
971 |
}
|
moel@345
|
972 |
|
moel@345
|
973 |
private TreeNodeAdv FindNode(TreeNodeAdv root, TreePath path, int level, bool readChilds)
|
moel@345
|
974 |
{
|
moel@345
|
975 |
if (!root.IsExpandedOnce && readChilds)
|
moel@345
|
976 |
ReadChilds(root);
|
moel@345
|
977 |
|
moel@345
|
978 |
for (int i = 0; i < root.Nodes.Count; i++)
|
moel@345
|
979 |
{
|
moel@345
|
980 |
TreeNodeAdv node = root.Nodes[i];
|
moel@345
|
981 |
if (node.Tag == path.FullPath[level])
|
moel@345
|
982 |
{
|
moel@345
|
983 |
if (level == path.FullPath.Length - 1)
|
moel@345
|
984 |
return node;
|
moel@345
|
985 |
else
|
moel@345
|
986 |
return FindNode(node, path, level + 1, readChilds);
|
moel@345
|
987 |
}
|
moel@345
|
988 |
}
|
moel@345
|
989 |
return null;
|
moel@345
|
990 |
}
|
moel@345
|
991 |
|
moel@345
|
992 |
public TreeNodeAdv FindNodeByTag(object tag)
|
moel@345
|
993 |
{
|
moel@345
|
994 |
return FindNodeByTag(_root, tag);
|
moel@345
|
995 |
}
|
moel@345
|
996 |
|
moel@345
|
997 |
private TreeNodeAdv FindNodeByTag(TreeNodeAdv root, object tag)
|
moel@345
|
998 |
{
|
moel@345
|
999 |
foreach (TreeNodeAdv node in root.Nodes)
|
moel@345
|
1000 |
{
|
moel@345
|
1001 |
if (node.Tag == tag)
|
moel@345
|
1002 |
return node;
|
moel@345
|
1003 |
TreeNodeAdv res = FindNodeByTag(node, tag);
|
moel@345
|
1004 |
if (res != null)
|
moel@345
|
1005 |
return res;
|
moel@345
|
1006 |
}
|
moel@345
|
1007 |
return null;
|
moel@345
|
1008 |
}
|
moel@345
|
1009 |
|
moel@345
|
1010 |
public void SelectAllNodes()
|
moel@345
|
1011 |
{
|
moel@345
|
1012 |
SuspendSelectionEvent = true;
|
moel@345
|
1013 |
try
|
moel@345
|
1014 |
{
|
moel@345
|
1015 |
if (SelectionMode == TreeSelectionMode.MultiSameParent)
|
moel@345
|
1016 |
{
|
moel@345
|
1017 |
if (CurrentNode != null)
|
moel@345
|
1018 |
{
|
moel@345
|
1019 |
foreach (TreeNodeAdv n in CurrentNode.Parent.Nodes)
|
moel@345
|
1020 |
n.IsSelected = true;
|
moel@345
|
1021 |
}
|
moel@345
|
1022 |
}
|
moel@345
|
1023 |
else if (SelectionMode == TreeSelectionMode.Multi)
|
moel@345
|
1024 |
{
|
moel@345
|
1025 |
SelectNodes(Root.Nodes);
|
moel@345
|
1026 |
}
|
moel@345
|
1027 |
}
|
moel@345
|
1028 |
finally
|
moel@345
|
1029 |
{
|
moel@345
|
1030 |
SuspendSelectionEvent = false;
|
moel@345
|
1031 |
}
|
moel@345
|
1032 |
}
|
moel@345
|
1033 |
|
moel@345
|
1034 |
private void SelectNodes(Collection<TreeNodeAdv> nodes)
|
moel@345
|
1035 |
{
|
moel@345
|
1036 |
foreach (TreeNodeAdv n in nodes)
|
moel@345
|
1037 |
{
|
moel@345
|
1038 |
n.IsSelected = true;
|
moel@345
|
1039 |
if (n.IsExpanded)
|
moel@345
|
1040 |
SelectNodes(n.Nodes);
|
moel@345
|
1041 |
}
|
moel@345
|
1042 |
}
|
moel@345
|
1043 |
|
moel@345
|
1044 |
#region ModelEvents
|
moel@345
|
1045 |
private void BindModelEvents()
|
moel@345
|
1046 |
{
|
moel@345
|
1047 |
_model.NodesChanged += new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
|
moel@345
|
1048 |
_model.NodesInserted += new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
|
moel@345
|
1049 |
_model.NodesRemoved += new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
|
moel@345
|
1050 |
_model.StructureChanged += new EventHandler<TreePathEventArgs>(_model_StructureChanged);
|
moel@345
|
1051 |
}
|
moel@345
|
1052 |
|
moel@345
|
1053 |
private void UnbindModelEvents()
|
moel@345
|
1054 |
{
|
moel@345
|
1055 |
_model.NodesChanged -= new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
|
moel@345
|
1056 |
_model.NodesInserted -= new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
|
moel@345
|
1057 |
_model.NodesRemoved -= new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
|
moel@345
|
1058 |
_model.StructureChanged -= new EventHandler<TreePathEventArgs>(_model_StructureChanged);
|
moel@345
|
1059 |
}
|
moel@345
|
1060 |
|
moel@345
|
1061 |
private void _model_StructureChanged(object sender, TreePathEventArgs e)
|
moel@345
|
1062 |
{
|
moel@345
|
1063 |
if (e.Path == null)
|
moel@345
|
1064 |
throw new ArgumentNullException();
|
moel@345
|
1065 |
|
moel@345
|
1066 |
TreeNodeAdv node = FindNode(e.Path);
|
moel@345
|
1067 |
if (node != null)
|
moel@345
|
1068 |
{
|
moel@345
|
1069 |
if (node != Root)
|
moel@345
|
1070 |
node.IsLeaf = Model.IsLeaf(GetPath(node));
|
moel@345
|
1071 |
|
moel@345
|
1072 |
var list = new Dictionary<object, object>();
|
moel@345
|
1073 |
SaveExpandedNodes(node, list);
|
moel@345
|
1074 |
ReadChilds(node);
|
moel@345
|
1075 |
RestoreExpandedNodes(node, list);
|
moel@345
|
1076 |
|
moel@345
|
1077 |
UpdateSelection();
|
moel@345
|
1078 |
SmartFullUpdate();
|
moel@345
|
1079 |
}
|
moel@345
|
1080 |
//else
|
moel@345
|
1081 |
// throw new ArgumentException("Path not found");
|
moel@345
|
1082 |
}
|
moel@345
|
1083 |
|
moel@345
|
1084 |
private void RestoreExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
|
moel@345
|
1085 |
{
|
moel@345
|
1086 |
if (node.Tag != null && list.ContainsKey(node.Tag))
|
moel@345
|
1087 |
{
|
moel@345
|
1088 |
node.IsExpanded = true;
|
moel@345
|
1089 |
foreach (var child in node.Children)
|
moel@345
|
1090 |
RestoreExpandedNodes(child, list);
|
moel@345
|
1091 |
}
|
moel@345
|
1092 |
}
|
moel@345
|
1093 |
|
moel@345
|
1094 |
private void SaveExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
|
moel@345
|
1095 |
{
|
moel@345
|
1096 |
if (node.IsExpanded && node.Tag != null)
|
moel@345
|
1097 |
{
|
moel@345
|
1098 |
list.Add(node.Tag, null);
|
moel@345
|
1099 |
foreach (var child in node.Children)
|
moel@345
|
1100 |
SaveExpandedNodes(child, list);
|
moel@345
|
1101 |
}
|
moel@345
|
1102 |
}
|
moel@345
|
1103 |
|
moel@345
|
1104 |
private void _model_NodesRemoved(object sender, TreeModelEventArgs e)
|
moel@345
|
1105 |
{
|
moel@345
|
1106 |
TreeNodeAdv parent = FindNode(e.Path);
|
moel@345
|
1107 |
if (parent != null)
|
moel@345
|
1108 |
{
|
moel@345
|
1109 |
if (e.Indices != null)
|
moel@345
|
1110 |
{
|
moel@345
|
1111 |
List<int> list = new List<int>(e.Indices);
|
moel@345
|
1112 |
list.Sort();
|
moel@345
|
1113 |
for (int n = list.Count - 1; n >= 0; n--)
|
moel@345
|
1114 |
{
|
moel@345
|
1115 |
int index = list[n];
|
moel@345
|
1116 |
if (index >= 0 && index <= parent.Nodes.Count)
|
moel@345
|
1117 |
parent.Nodes.RemoveAt(index);
|
moel@345
|
1118 |
else
|
moel@345
|
1119 |
throw new ArgumentOutOfRangeException("Index out of range");
|
moel@345
|
1120 |
}
|
moel@345
|
1121 |
}
|
moel@345
|
1122 |
else
|
moel@345
|
1123 |
{
|
moel@345
|
1124 |
for (int i = parent.Nodes.Count - 1; i >= 0; i--)
|
moel@345
|
1125 |
{
|
moel@345
|
1126 |
for (int n = 0; n < e.Children.Length; n++)
|
moel@345
|
1127 |
if (parent.Nodes[i].Tag == e.Children[n])
|
moel@345
|
1128 |
{
|
moel@345
|
1129 |
parent.Nodes.RemoveAt(i);
|
moel@345
|
1130 |
break;
|
moel@345
|
1131 |
}
|
moel@345
|
1132 |
}
|
moel@345
|
1133 |
}
|
moel@345
|
1134 |
}
|
moel@345
|
1135 |
UpdateSelection();
|
moel@345
|
1136 |
SmartFullUpdate();
|
moel@345
|
1137 |
}
|
moel@345
|
1138 |
|
moel@345
|
1139 |
private void _model_NodesInserted(object sender, TreeModelEventArgs e)
|
moel@345
|
1140 |
{
|
moel@345
|
1141 |
if (e.Indices == null)
|
moel@345
|
1142 |
throw new ArgumentNullException("Indices");
|
moel@345
|
1143 |
|
moel@345
|
1144 |
TreeNodeAdv parent = FindNode(e.Path);
|
moel@345
|
1145 |
if (parent != null)
|
moel@345
|
1146 |
{
|
moel@345
|
1147 |
for (int i = 0; i < e.Children.Length; i++)
|
moel@345
|
1148 |
AddNewNode(parent, e.Children[i], e.Indices[i]);
|
moel@345
|
1149 |
}
|
moel@345
|
1150 |
SmartFullUpdate();
|
moel@345
|
1151 |
}
|
moel@345
|
1152 |
|
moel@345
|
1153 |
private void _model_NodesChanged(object sender, TreeModelEventArgs e)
|
moel@345
|
1154 |
{
|
moel@345
|
1155 |
TreeNodeAdv parent = FindNode(e.Path);
|
moel@345
|
1156 |
if (parent != null && parent.IsVisible && parent.IsExpanded)
|
moel@345
|
1157 |
{
|
moel@345
|
1158 |
if (InvokeRequired)
|
moel@345
|
1159 |
BeginInvoke(new UpdateContentWidthDelegate(ClearNodesSize), e, parent);
|
moel@345
|
1160 |
else
|
moel@345
|
1161 |
ClearNodesSize(e, parent);
|
moel@345
|
1162 |
SmartFullUpdate();
|
moel@345
|
1163 |
}
|
moel@345
|
1164 |
}
|
moel@345
|
1165 |
|
moel@345
|
1166 |
private delegate void UpdateContentWidthDelegate(TreeModelEventArgs e, TreeNodeAdv parent);
|
moel@345
|
1167 |
private void ClearNodesSize(TreeModelEventArgs e, TreeNodeAdv parent)
|
moel@345
|
1168 |
{
|
moel@345
|
1169 |
if (e.Indices != null)
|
moel@345
|
1170 |
{
|
moel@345
|
1171 |
foreach (int index in e.Indices)
|
moel@345
|
1172 |
{
|
moel@345
|
1173 |
if (index >= 0 && index < parent.Nodes.Count)
|
moel@345
|
1174 |
{
|
moel@345
|
1175 |
TreeNodeAdv node = parent.Nodes[index];
|
moel@345
|
1176 |
node.Height = node.RightBounds = null;
|
moel@345
|
1177 |
}
|
moel@345
|
1178 |
else
|
moel@345
|
1179 |
throw new ArgumentOutOfRangeException("Index out of range");
|
moel@345
|
1180 |
}
|
moel@345
|
1181 |
}
|
moel@345
|
1182 |
else
|
moel@345
|
1183 |
{
|
moel@345
|
1184 |
foreach (TreeNodeAdv node in parent.Nodes)
|
moel@345
|
1185 |
{
|
moel@345
|
1186 |
foreach (object obj in e.Children)
|
moel@345
|
1187 |
if (node.Tag == obj)
|
moel@345
|
1188 |
{
|
moel@345
|
1189 |
node.Height = node.RightBounds = null;
|
moel@345
|
1190 |
}
|
moel@345
|
1191 |
}
|
moel@345
|
1192 |
}
|
moel@345
|
1193 |
}
|
moel@345
|
1194 |
#endregion
|
moel@345
|
1195 |
}
|
moel@345
|
1196 |
}
|