diff options
author | Mike Krüger <mkrueger@xamarin.com> | 2012-06-01 13:58:12 +0400 |
---|---|---|
committer | Mike Krüger <mkrueger@xamarin.com> | 2012-06-01 13:58:12 +0400 |
commit | a7f6566e54399bc4790ff01741a09388126593e4 (patch) | |
tree | e9f61de704d77b22c1568f0173663f1a5a75196b /main | |
parent | 99ae3e0355c89022a690daa56875c2b6978e1662 (diff) |
[TextEditor] Height tree is now thread safe.
Diffstat (limited to 'main')
-rw-r--r-- | main/src/core/Mono.Texteditor/Mono.TextEditor/HeightTree.cs | 412 |
1 files changed, 214 insertions, 198 deletions
diff --git a/main/src/core/Mono.Texteditor/Mono.TextEditor/HeightTree.cs b/main/src/core/Mono.Texteditor/Mono.TextEditor/HeightTree.cs index 5f1ce13dbc..107ff9cbd9 100644 --- a/main/src/core/Mono.Texteditor/Mono.TextEditor/HeightTree.cs +++ b/main/src/core/Mono.Texteditor/Mono.TextEditor/HeightTree.cs @@ -42,7 +42,6 @@ namespace Mono.TextEditor // TODO: Add support for line word wrap to the text editor - with the height tree this is possible. internal RedBlackTree<HeightNode> tree = new RedBlackTree<HeightNode> (); readonly TextEditorData editor; - readonly Thread guiThread; public double TotalHeight { get { @@ -58,19 +57,12 @@ namespace Mono.TextEditor public HeightTree (TextEditorData editor) { - guiThread = Thread.CurrentThread; this.editor = editor; this.editor.Document.Splitter.LineRemoved += HandleLineRemoved; this.editor.Document.Splitter.LineInserted += HandleLineInserted; this.editor.Document.FoldTreeUpdated += HandleFoldTreeUpdated; } - void CheckThread () - { - if (guiThread != Thread.CurrentThread) - throw new InvalidOperationException ("Called from the wrong thread."); - } - void HandleLineInserted (object sender, LineEventArgs e) { InsertLine (e.Line.LineNumber); @@ -97,18 +89,19 @@ namespace Mono.TextEditor void RemoveLine (int line) { - CheckThread (); - try { - var node = GetNodeByLine (line); - if (node == null) - return; - if (node.count == 1) { - tree.Remove (node); - return; + lock (tree) { + try { + var node = GetNodeByLine (line); + if (node == null) + return; + if (node.count == 1) { + tree.Remove (node); + return; + } + node.count--; + } finally { + OnLineUpdateFrom (new HeightChangedEventArgs (line - 1)); } - node.count--; - } finally { - OnLineUpdateFrom (new HeightChangedEventArgs (line - 1)); } } @@ -135,103 +128,108 @@ namespace Mono.TextEditor void InsertLine (int line) { - CheckThread (); - var newLine = new HeightNode () { - count = 1, - height = editor.LineHeight - }; + lock (tree) { + var newLine = new HeightNode () { + count = 1, + height = editor.LineHeight + }; - try { - if (line == tree.Root.totalCount + 1) { - tree.InsertAfter (tree.Root.GetOuterRight (), newLine); - return; - } - var node = GetNodeByLine (line); - if (node == null) - return; - if (node.count == 1) { - tree.InsertBefore (node, newLine); - return; + try { + if (line == tree.Root.totalCount + 1) { + tree.InsertAfter (tree.Root.GetOuterRight (), newLine); + return; + } + var node = GetNodeByLine (line); + if (node == null) + return; + if (node.count == 1) { + tree.InsertBefore (node, newLine); + return; + } + node.count++; + } finally { + newLine.UpdateAugmentedData (); + OnLineUpdateFrom (new HeightChangedEventArgs (line)); } - node.count++; - } finally { - newLine.UpdateAugmentedData (); - OnLineUpdateFrom (new HeightChangedEventArgs (line)); } } bool rebuild; public void Rebuild () { - CheckThread (); - rebuild = true; - try { - markers.Clear (); - tree.Count = 1; - double h = editor.LineCount * editor.LineHeight; - tree.Root = new HeightNode () { - height = h, - totalHeight = h, - totalCount = editor.LineCount, - totalVisibleCount = editor.LineCount, - count = editor.LineCount - }; - - foreach (var extendedTextMarkerLine in editor.Document.LinesWithExtendingTextMarkers) { - int lineNumber = extendedTextMarkerLine.LineNumber; - double height = editor.GetLineHeight (extendedTextMarkerLine); - SetLineHeight (lineNumber, height); - } - - foreach (var segment in editor.Document.FoldedSegments.ToArray ()) { - int start = editor.OffsetToLineNumber (segment.Offset); - int end = editor.OffsetToLineNumber (segment.EndOffset); - segment.Marker = Fold (start, end - start); + lock (tree) { + rebuild = true; + try { + markers.Clear (); + tree.Count = 1; + double h = editor.LineCount * editor.LineHeight; + tree.Root = new HeightNode () { + height = h, + totalHeight = h, + totalCount = editor.LineCount, + totalVisibleCount = editor.LineCount, + count = editor.LineCount + }; + + foreach (var extendedTextMarkerLine in editor.Document.LinesWithExtendingTextMarkers) { + int lineNumber = extendedTextMarkerLine.LineNumber; + double height = editor.GetLineHeight (extendedTextMarkerLine); + SetLineHeight (lineNumber, height); + } + + foreach (var segment in editor.Document.FoldedSegments.ToArray ()) { + int start = editor.OffsetToLineNumber (segment.Offset); + int end = editor.OffsetToLineNumber (segment.EndOffset); + segment.Marker = Fold (start, end - start); + } + } finally { + rebuild = false; } - } finally { - rebuild = false; } } public void SetLineHeight (int lineNumber, double height) { - CheckThread (); - var node = GetNodeByLine (lineNumber); - if (node == null) - throw new Exception ("No node for line number " + lineNumber + " found. (maxLine=" + tree.Root.totalCount + ")"); - int nodeStartLine = node.GetLineNumber (); - int remainingLineCount; - if (nodeStartLine == lineNumber) { - remainingLineCount = node.count - 1; - ChangeHeight (node, 1, height); - if (remainingLineCount > 0) { - InsertAfter (node, new HeightNode () { - count = remainingLineCount, - height = editor.LineHeight * remainingLineCount, - foldLevel = node.foldLevel - }); - } - } else { - int newLineCount = lineNumber - nodeStartLine; - remainingLineCount = node.count - newLineCount - 1; - if (newLineCount != node.count) { - double newHeight = editor.LineHeight * newLineCount; - ChangeHeight (node, newLineCount, newHeight); - } - - var newNode = new HeightNode () { - count = 1, - height = height, - foldLevel = node.foldLevel - }; - InsertAfter (node, newNode); - - if (remainingLineCount > 0) { - InsertAfter (newNode, new HeightNode () { - count = remainingLineCount, - height = editor.LineHeight * remainingLineCount, + lock (tree) { + var node = GetNodeByLine (lineNumber); + if (node == null) + throw new Exception ("No node for line number " + lineNumber + " found. (maxLine=" + tree.Root.totalCount + ")"); + int nodeStartLine = node.GetLineNumber (); + int remainingLineCount; + if (nodeStartLine == lineNumber) { + remainingLineCount = node.count - 1; + ChangeHeight (node, 1, height); + if (remainingLineCount > 0) { + InsertAfter (node, new HeightNode () { + count = remainingLineCount, + height = editor.LineHeight * remainingLineCount, + foldLevel = node.foldLevel + } + ); + } + } else { + int newLineCount = lineNumber - nodeStartLine; + remainingLineCount = node.count - newLineCount - 1; + if (newLineCount != node.count) { + double newHeight = editor.LineHeight * newLineCount; + ChangeHeight (node, newLineCount, newHeight); + } + + var newNode = new HeightNode () { + count = 1, + height = height, foldLevel = node.foldLevel - }); + }; + InsertAfter (node, newNode); + + if (remainingLineCount > 0) { + InsertAfter (newNode, new HeightNode () { + count = remainingLineCount, + height = editor.LineHeight * remainingLineCount, + foldLevel = node.foldLevel + } + ); + } } } OnLineUpdateFrom (new HeightChangedEventArgs (lineNumber)); @@ -253,97 +251,109 @@ namespace Mono.TextEditor public FoldMarker Fold (int lineNumber, int count) { - CheckThread (); - GetSingleLineNode (lineNumber); - lineNumber++; - - for (int i = lineNumber; i < lineNumber + count; i++) { - var node = GetSingleLineNode (i); - node.foldLevel++; - node.UpdateAugmentedData (); + lock (tree) { + GetSingleLineNode (lineNumber); + lineNumber++; + + for (int i = lineNumber; i < lineNumber + count; i++) { + var node = GetSingleLineNode (i); + node.foldLevel++; + node.UpdateAugmentedData (); + } + var result = new FoldMarker (lineNumber, count); + markers.Add (result); + OnLineUpdateFrom (new HeightChangedEventArgs (lineNumber - 1)); + return result; } - var result = new FoldMarker (lineNumber, count); - markers.Add (result); - OnLineUpdateFrom (new HeightChangedEventArgs (lineNumber - 1)); - return result; } public void Unfold (FoldMarker marker, int lineNumber, int count) { - CheckThread (); - if (marker == null || !markers.Contains (marker)) - return; - markers.Remove (marker); - - GetSingleLineNode (lineNumber); - lineNumber++; - for (int i = lineNumber; i < lineNumber + count; i++) { - var node = GetSingleLineNode (i); - node.foldLevel--; - node.UpdateAugmentedData (); + lock (tree) { + if (marker == null || !markers.Contains (marker)) + return; + markers.Remove (marker); + + GetSingleLineNode (lineNumber); + lineNumber++; + for (int i = lineNumber; i < lineNumber + count; i++) { + var node = GetSingleLineNode (i); + node.foldLevel--; + node.UpdateAugmentedData (); + } + OnLineUpdateFrom (new HeightChangedEventArgs (lineNumber - 1)); } - OnLineUpdateFrom (new HeightChangedEventArgs (lineNumber - 1)); } public double LineNumberToY (int lineNumber) { - var node = GetSingleLineNode (lineNumber); - int ln = lineNumber - 1; - while (ln > 0 && node != null && node.foldLevel > 0) { - node = GetSingleLineNode (ln--); - } - if (ln == 0 || node == null) - return 0; - double result = node.Left != null ? ((HeightNode)node.Left).totalHeight : 0; - - while (node.parent != null) { - if (node == node.parent.right) { - if (node.parent.left != null) { - result += node.parent.left.totalHeight; - } - if (node.parent.foldLevel == 0) { - result += node.parent.height; + lock (tree) { + var node = GetSingleLineNode (lineNumber); + int ln = lineNumber - 1; + while (ln > 0 && node != null && node.foldLevel > 0) { + node = GetSingleLineNode (ln--); + } + if (ln == 0 || node == null) + return 0; + double result = node.Left != null ? ((HeightNode)node.Left).totalHeight : 0; + + while (node.parent != null) { + if (node == node.parent.right) { + if (node.parent.left != null) { + result += node.parent.left.totalHeight; + } + if (node.parent.foldLevel == 0) { + result += node.parent.height; + } } + node = node.parent; } - node = node.parent; + return result; } - return result; } public int YToLineNumber (double y) { - var node = GetNodeByY (y); - if (node == null) - return y < 0 ? DocumentLocation.MinLine + (int)(y / editor.LineHeight) : tree.Root.totalCount + (int)((y - tree.Root.totalHeight) / editor.LineHeight); - int lineOffset = 0; - if (node.foldLevel == 0) { - double delta = y - node.GetY (); - lineOffset = (int)(node.count * delta / node.height); + lock (tree) { + var node = GetNodeByY (y); + if (node == null) + return y < 0 ? DocumentLocation.MinLine + (int)(y / editor.LineHeight) : tree.Root.totalCount + (int)((y - tree.Root.totalHeight) / editor.LineHeight); + int lineOffset = 0; + if (node.foldLevel == 0) { + double delta = y - node.GetY (); + lineOffset = (int)(node.count * delta / node.height); + } + return node.GetLineNumber () + lineOffset; } - return node.GetLineNumber () + lineOffset; } void InsertAfter (HeightNode node, HeightNode newNode) { - if (newNode.count <= 0) - throw new ArgumentOutOfRangeException ("new node count <= 0."); - tree.InsertAfter (node, newNode); - newNode.UpdateAugmentedData (); + lock (tree) { + if (newNode.count <= 0) + throw new ArgumentOutOfRangeException ("new node count <= 0."); + tree.InsertAfter (node, newNode); + newNode.UpdateAugmentedData (); + } } void InsertBefore (HeightNode node, HeightNode newNode) { - if (newNode.count <= 0) - throw new ArgumentOutOfRangeException ("new node count <= 0."); - tree.InsertBefore (node, newNode); - newNode.UpdateAugmentedData (); + lock (tree) { + if (newNode.count <= 0) + throw new ArgumentOutOfRangeException ("new node count <= 0."); + tree.InsertBefore (node, newNode); + newNode.UpdateAugmentedData (); + } } void ChangeHeight (HeightNode node, int newCount, double newHeight) { - node.count = newCount; - node.height = newHeight; - node.UpdateAugmentedData (); + lock (tree) { + node.count = newCount; + node.height = newHeight; + node.UpdateAugmentedData (); + } } int GetValidLine (int logicalLine) @@ -357,16 +367,18 @@ namespace Mono.TextEditor public int LogicalToVisualLine (int logicalLine) { - if (logicalLine < DocumentLocation.MinLine) - return DocumentLocation.MinLine; - if (logicalLine > tree.Root.totalCount) - return tree.Root.totalCount + logicalLine - tree.Root.totalCount; - int line = GetValidLine (logicalLine); - var node = GetNodeByLine (line); - if (node == null) - return tree.Root.totalCount + logicalLine - tree.Root.totalCount; - int delta = logicalLine - node.GetLineNumber (); - return node.GetVisibleLineNumber () + delta; + lock (tree) { + if (logicalLine < DocumentLocation.MinLine) + return DocumentLocation.MinLine; + if (logicalLine > tree.Root.totalCount) + return tree.Root.totalCount + logicalLine - tree.Root.totalCount; + int line = GetValidLine (logicalLine); + var node = GetNodeByLine (line); + if (node == null) + return tree.Root.totalCount + logicalLine - tree.Root.totalCount; + int delta = logicalLine - node.GetLineNumber (); + return node.GetVisibleLineNumber () + delta; + } } int GetValidVisualLine (int logicalLine) @@ -380,16 +392,18 @@ namespace Mono.TextEditor public int VisualToLogicalLine (int visualLineNumber) { - if (visualLineNumber < DocumentLocation.MinLine) - return DocumentLocation.MinLine; - if (visualLineNumber > tree.Root.totalVisibleCount) - return tree.Root.totalCount + visualLineNumber - tree.Root.totalVisibleCount; - int line = GetValidVisualLine (visualLineNumber); - var node = GetNodeByVisibleLine (line); - if (node == null) - return tree.Root.totalCount + visualLineNumber - tree.Root.totalVisibleCount; - int delta = visualLineNumber - node.GetVisibleLineNumber (); - return node.GetLineNumber () + delta; + lock (tree) { + if (visualLineNumber < DocumentLocation.MinLine) + return DocumentLocation.MinLine; + if (visualLineNumber > tree.Root.totalVisibleCount) + return tree.Root.totalCount + visualLineNumber - tree.Root.totalVisibleCount; + int line = GetValidVisualLine (visualLineNumber); + var node = GetNodeByVisibleLine (line); + if (node == null) + return tree.Root.totalCount + visualLineNumber - tree.Root.totalVisibleCount; + int delta = visualLineNumber - node.GetVisibleLineNumber (); + return node.GetLineNumber () + delta; + } } HeightNode GetSingleLineNode (int lineNumber) @@ -432,25 +446,27 @@ namespace Mono.TextEditor public HeightNode GetNodeByLine (int lineNumber) { - var node = tree.Root; - int i = lineNumber - 1; - while (true) { - if (node == null) - return null; - if (node.left != null && i < node.left.totalCount) { - node = node.left; - } else { - if (node.left != null) - i -= node.left.totalCount; - i -= node.count; - if (i < 0) - return node; - node = node.right; + lock (tree) { + var node = tree.Root; + int i = lineNumber - 1; + while (true) { + if (node == null) + return null; + if (node.left != null && i < node.left.totalCount) { + node = node.left; + } else { + if (node.left != null) + i -= node.left.totalCount; + i -= node.count; + if (i < 0) + return node; + node = node.right; + } } } } - public HeightNode GetNodeByVisibleLine (int lineNumber) + HeightNode GetNodeByVisibleLine (int lineNumber) { var node = tree.Root; int i = lineNumber - 1; @@ -471,7 +487,7 @@ namespace Mono.TextEditor } } - public HeightNode GetNodeByY (double y) + HeightNode GetNodeByY (double y) { var node = tree.Root; double h = y; |