Code Coverage Statistics for Source File
c:\Tools\SD3\src\Libraries\ICSharpCode.TextEditor\Project\Src\Gui\TextEditorControl.cs
|
Sequence Point Coverage
N/A
0 of 0
|
Branch Coverage
N/A
0 of 0
|
Lines
393
|
Highlight:
Uncovered Code
Covered Code
| L | V | Source |
|---|---|---|
1 |
// <file> |
|
2 |
// <copyright see="prj:///doc/copyright.txt"/> |
|
3 |
// <license see="prj:///doc/license.txt"/> |
|
4 |
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/> |
|
5 |
// <version>$Revision: 2683 $</version> |
|
6 |
// </file> |
|
7 |
||
8 |
using System; |
|
9 |
using System.ComponentModel; |
|
10 |
using System.Drawing; |
|
11 |
using System.Drawing.Printing; |
|
12 |
using System.Windows.Forms; |
|
13 |
||
14 |
using ICSharpCode.TextEditor.Document; |
|
15 |
||
16 |
namespace ICSharpCode.TextEditor |
|
17 |
{ |
|
18 |
/// <summary> |
|
19 |
/// This class is used for a basic text area control |
|
20 |
/// </summary> |
|
21 |
[ToolboxBitmap("ICSharpCode.TextEditor.Resources.TextEditorControl.bmp")] |
|
22 |
[ToolboxItem(true)] |
|
23 |
public class TextEditorControl : TextEditorControlBase |
|
24 |
{ |
|
25 |
protected Panel textAreaPanel = new Panel(); |
|
26 |
TextAreaControl primaryTextArea; |
|
27 |
Splitter textAreaSplitter = null; |
|
28 |
TextAreaControl secondaryTextArea = null; |
|
29 |
||
30 |
PrintDocument printDocument = null; |
|
31 |
||
32 |
[Browsable(false)] |
|
33 |
public PrintDocument PrintDocument { |
|
34 |
get { |
|
35 |
if (printDocument == null) { |
|
36 |
printDocument = new PrintDocument(); |
|
37 |
printDocument.BeginPrint += new PrintEventHandler(this.BeginPrint); |
|
38 |
printDocument.PrintPage += new PrintPageEventHandler(this.PrintPage); |
|
39 |
} |
|
40 |
return printDocument; |
|
41 |
} |
|
42 |
} |
|
43 |
||
44 |
TextAreaControl activeTextAreaControl; |
|
45 |
||
46 |
public override TextAreaControl ActiveTextAreaControl { |
|
47 |
get { |
|
48 |
return activeTextAreaControl; |
|
49 |
} |
|
50 |
} |
|
51 |
||
52 |
protected void SetActiveTextAreaControl(TextAreaControl value) |
|
53 |
{ |
|
54 |
if (activeTextAreaControl != value) { |
|
55 |
activeTextAreaControl = value; |
|
56 |
||
57 |
if (ActiveTextAreaControlChanged != null) { |
|
58 |
ActiveTextAreaControlChanged(this, EventArgs.Empty); |
|
59 |
} |
|
60 |
} |
|
61 |
} |
|
62 |
||
63 |
public event EventHandler ActiveTextAreaControlChanged; |
|
64 |
||
65 |
public TextEditorControl() |
|
66 |
{ |
|
67 |
SetStyle(ControlStyles.ContainerControl, true); |
|
68 |
||
69 |
textAreaPanel.Dock = DockStyle.Fill; |
|
70 |
||
71 |
Document = (new DocumentFactory()).CreateDocument(); |
|
72 |
Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy(); |
|
73 |
||
74 |
primaryTextArea = new TextAreaControl(this); |
|
75 |
activeTextAreaControl = primaryTextArea; |
|
76 |
primaryTextArea.TextArea.GotFocus += delegate { |
|
77 |
SetActiveTextAreaControl(primaryTextArea); |
|
78 |
}; |
|
79 |
primaryTextArea.Dock = DockStyle.Fill; |
|
80 |
textAreaPanel.Controls.Add(primaryTextArea); |
|
81 |
InitializeTextAreaControl(primaryTextArea); |
|
82 |
Controls.Add(textAreaPanel); |
|
83 |
ResizeRedraw = true; |
|
84 |
Document.UpdateCommited += new EventHandler(CommitUpdateRequested); |
|
85 |
OptionsChanged(); |
|
86 |
} |
|
87 |
||
88 |
protected virtual void InitializeTextAreaControl(TextAreaControl newControl) |
|
89 |
{ |
|
90 |
} |
|
91 |
||
92 |
public override void OptionsChanged() |
|
93 |
{ |
|
94 |
primaryTextArea.OptionsChanged(); |
|
95 |
if (secondaryTextArea != null) { |
|
96 |
secondaryTextArea.OptionsChanged(); |
|
97 |
} |
|
98 |
} |
|
99 |
||
100 |
public void Split() |
|
101 |
{ |
|
102 |
if (secondaryTextArea == null) { |
|
103 |
secondaryTextArea = new TextAreaControl(this); |
|
104 |
secondaryTextArea.Dock = DockStyle.Bottom; |
|
105 |
secondaryTextArea.Height = Height / 2; |
|
106 |
||
107 |
secondaryTextArea.TextArea.GotFocus += delegate { |
|
108 |
SetActiveTextAreaControl(secondaryTextArea); |
|
109 |
}; |
|
110 |
||
111 |
textAreaSplitter = new Splitter(); |
|
112 |
textAreaSplitter.BorderStyle = BorderStyle.FixedSingle ; |
|
113 |
textAreaSplitter.Height = 8; |
|
114 |
textAreaSplitter.Dock = DockStyle.Bottom; |
|
115 |
textAreaPanel.Controls.Add(textAreaSplitter); |
|
116 |
textAreaPanel.Controls.Add(secondaryTextArea); |
|
117 |
InitializeTextAreaControl(secondaryTextArea); |
|
118 |
secondaryTextArea.OptionsChanged(); |
|
119 |
} else { |
|
120 |
SetActiveTextAreaControl(primaryTextArea); |
|
121 |
||
122 |
textAreaPanel.Controls.Remove(secondaryTextArea); |
|
123 |
textAreaPanel.Controls.Remove(textAreaSplitter); |
|
124 |
||
125 |
secondaryTextArea.Dispose(); |
|
126 |
textAreaSplitter.Dispose(); |
|
127 |
secondaryTextArea = null; |
|
128 |
textAreaSplitter = null; |
|
129 |
} |
|
130 |
} |
|
131 |
||
132 |
[Browsable(false)] |
|
133 |
public bool EnableUndo { |
|
134 |
get { |
|
135 |
return Document.UndoStack.CanUndo; |
|
136 |
} |
|
137 |
} |
|
138 |
||
139 |
[Browsable(false)] |
|
140 |
public bool EnableRedo { |
|
141 |
get { |
|
142 |
return Document.UndoStack.CanRedo; |
|
143 |
} |
|
144 |
} |
|
145 |
||
146 |
public void Undo() |
|
147 |
{ |
|
148 |
if (Document.ReadOnly) { |
|
149 |
return; |
|
150 |
} |
|
151 |
if (Document.UndoStack.CanUndo) { |
|
152 |
BeginUpdate(); |
|
153 |
Document.UndoStack.Undo(); |
|
154 |
||
155 |
Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea)); |
|
156 |
this.primaryTextArea.TextArea.UpdateMatchingBracket(); |
|
157 |
if (secondaryTextArea != null) { |
|
158 |
this.secondaryTextArea.TextArea.UpdateMatchingBracket(); |
|
159 |
} |
|
160 |
EndUpdate(); |
|
161 |
} |
|
162 |
} |
|
163 |
||
164 |
public void Redo() |
|
165 |
{ |
|
166 |
if (Document.ReadOnly) { |
|
167 |
return; |
|
168 |
} |
|
169 |
if (Document.UndoStack.CanRedo) { |
|
170 |
BeginUpdate(); |
|
171 |
Document.UndoStack.Redo(); |
|
172 |
||
173 |
Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea)); |
|
174 |
this.primaryTextArea.TextArea.UpdateMatchingBracket(); |
|
175 |
if (secondaryTextArea != null) { |
|
176 |
this.secondaryTextArea.TextArea.UpdateMatchingBracket(); |
|
177 |
} |
|
178 |
EndUpdate(); |
|
179 |
} |
|
180 |
} |
|
181 |
||
182 |
public void SetHighlighting(string name) |
|
183 |
{ |
|
184 |
Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy(name); |
|
185 |
} |
|
186 |
||
187 |
protected override void Dispose(bool disposing) |
|
188 |
{ |
|
189 |
if (disposing) { |
|
190 |
if (printDocument != null) { |
|
191 |
printDocument.BeginPrint -= new PrintEventHandler(this.BeginPrint); |
|
192 |
printDocument.PrintPage -= new PrintPageEventHandler(this.PrintPage); |
|
193 |
printDocument = null; |
|
194 |
} |
|
195 |
Document.UndoStack.ClearAll(); |
|
196 |
Document.UpdateCommited -= new EventHandler(CommitUpdateRequested); |
|
197 |
if (textAreaPanel != null) { |
|
198 |
if (secondaryTextArea != null) { |
|
199 |
secondaryTextArea.Dispose(); |
|
200 |
textAreaSplitter.Dispose(); |
|
201 |
secondaryTextArea = null; |
|
202 |
textAreaSplitter = null; |
|
203 |
} |
|
204 |
if (primaryTextArea != null) { |
|
205 |
primaryTextArea.Dispose(); |
|
206 |
} |
|
207 |
textAreaPanel.Dispose(); |
|
208 |
textAreaPanel = null; |
|
209 |
} |
|
210 |
} |
|
211 |
base.Dispose(disposing); |
|
212 |
} |
|
213 |
||
214 |
#region Update Methods |
|
215 |
public override void EndUpdate() |
|
216 |
{ |
|
217 |
base.EndUpdate(); |
|
218 |
Document.CommitUpdate(); |
|
219 |
} |
|
220 |
||
221 |
void CommitUpdateRequested(object sender, EventArgs e) |
|
222 |
{ |
|
223 |
if (IsInUpdate) { |
|
224 |
return; |
|
225 |
} |
|
226 |
foreach (TextAreaUpdate update in Document.UpdateQueue) { |
|
227 |
switch (update.TextAreaUpdateType) { |
|
228 |
case TextAreaUpdateType.PositionToEnd: |
|
229 |
this.primaryTextArea.TextArea.UpdateToEnd(update.Position.Y); |
|
230 |
if (this.secondaryTextArea != null) { |
|
231 |
this.secondaryTextArea.TextArea.UpdateToEnd(update.Position.Y); |
|
232 |
} |
|
233 |
break; |
|
234 |
case TextAreaUpdateType.PositionToLineEnd: |
|
235 |
case TextAreaUpdateType.SingleLine: |
|
236 |
this.primaryTextArea.TextArea.UpdateLine(update.Position.Y); |
|
237 |
if (this.secondaryTextArea != null) { |
|
238 |
this.secondaryTextArea.TextArea.UpdateLine(update.Position.Y); |
|
239 |
} |
|
240 |
break; |
|
241 |
case TextAreaUpdateType.SinglePosition: |
|
242 |
this.primaryTextArea.TextArea.UpdateLine(update.Position.Y, update.Position.X, update.Position.X); |
|
243 |
if (this.secondaryTextArea != null) { |
|
244 |
this.secondaryTextArea.TextArea.UpdateLine(update.Position.Y, update.Position.X, update.Position.X); |
|
245 |
} |
|
246 |
break; |
|
247 |
case TextAreaUpdateType.LinesBetween: |
|
248 |
this.primaryTextArea.TextArea.UpdateLines(update.Position.X, update.Position.Y); |
|
249 |
if (this.secondaryTextArea != null) { |
|
250 |
this.secondaryTextArea.TextArea.UpdateLines(update.Position.X, update.Position.Y); |
|
251 |
} |
|
252 |
break; |
|
253 |
case TextAreaUpdateType.WholeTextArea: |
|
254 |
this.primaryTextArea.TextArea.Invalidate(); |
|
255 |
if (this.secondaryTextArea != null) { |
|
256 |
this.secondaryTextArea.TextArea.Invalidate(); |
|
257 |
} |
|
258 |
break; |
|
259 |
} |
|
260 |
} |
|
261 |
Document.UpdateQueue.Clear(); |
|
262 |
// this.primaryTextArea.TextArea.Update(); |
|
263 |
// if (this.secondaryTextArea != null) { |
|
264 |
// this.secondaryTextArea.TextArea.Update(); |
|
265 |
// } |
|
266 |
} |
|
267 |
#endregion |
|
268 |
||
269 |
#region Printing routines |
|
270 |
int curLineNr = 0; |
|
271 |
float curTabIndent = 0; |
|
272 |
StringFormat printingStringFormat; |
|
273 |
||
274 |
void BeginPrint(object sender, PrintEventArgs ev) |
|
275 |
{ |
|
276 |
curLineNr = 0; |
|
277 |
printingStringFormat = (StringFormat)System.Drawing.StringFormat.GenericTypographic.Clone(); |
|
278 |
||
279 |
// 100 should be enough for everyone ...err ? |
|
280 |
float[] tabStops = new float[100]; |
|
281 |
for (int i = 0; i < tabStops.Length; ++i) { |
|
282 |
tabStops[i] = TabIndent * primaryTextArea.TextArea.TextView.WideSpaceWidth; |
|
283 |
} |
|
284 |
||
285 |
printingStringFormat.SetTabStops(0, tabStops); |
|
286 |
} |
|
287 |
||
288 |
void Advance(ref float x, ref float y, float maxWidth, float size, float fontHeight) |
|
289 |
{ |
|
290 |
if (x + size < maxWidth) { |
|
291 |
x += size; |
|
292 |
} else { |
|
293 |
x = curTabIndent; |
|
294 |
y += fontHeight; |
|
295 |
} |
|
296 |
} |
|
297 |
||
298 |
// btw. I hate source code duplication ... but this time I don't care !!!! |
|
299 |
float MeasurePrintingHeight(Graphics g, LineSegment line, float maxWidth) |
|
300 |
{ |
|
301 |
float xPos = 0; |
|
302 |
float yPos = 0; |
|
303 |
float fontHeight = Font.GetHeight(g); |
|
304 |
// bool gotNonWhitespace = false; |
|
305 |
curTabIndent = 0; |
|
306 |
FontContainer fontContainer = TextEditorProperties.FontContainer; |
|
307 |
foreach (TextWord word in line.Words) { |
|
308 |
switch (word.Type) { |
|
309 |
case TextWordType.Space: |
|
310 |
Advance(ref xPos, ref yPos, maxWidth, primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight); |
|
311 |
// if (!gotNonWhitespace) { |
|
312 |
// curTabIndent = xPos; |
|
313 |
// } |
|
314 |
break; |
|
315 |
case TextWordType.Tab: |
|
316 |
Advance(ref xPos, ref yPos, maxWidth, TabIndent * primaryTextArea.TextArea.TextView.WideSpaceWidth, fontHeight); |
|
317 |
// if (!gotNonWhitespace) { |
|
318 |
// curTabIndent = xPos; |
|
319 |
// } |
|
320 |
break; |
|
321 |
case TextWordType.Word: |
|
322 |
// if (!gotNonWhitespace) { |
|
323 |
// gotNonWhitespace = true; |
|
324 |
// curTabIndent += TabIndent * primaryTextArea.TextArea.TextView.GetWidth(' '); |
|
325 |
// } |
|
326 |
SizeF drawingSize = g.MeasureString(word.Word, word.GetFont(fontContainer), new SizeF(maxWidth, fontHeight * 100), printingStringFormat); |
|
327 |
Advance(ref xPos, ref yPos, maxWidth, drawingSize.Width, fontHeight); |
|
328 |
break; |
|
329 |
} |
|
330 |
} |
|
331 |
return yPos + fontHeight; |
|
332 |
} |
|
333 |
||
334 |
void DrawLine(Graphics g, LineSegment line, float yPos, RectangleF margin) |
|
335 |
{ |
|
336 |
float xPos = 0; |
|
337 |
float fontHeight = Font.GetHeight(g); |
|
338 |
// bool gotNonWhitespace = false; |
|
339 |
curTabIndent = 0 ; |
|
340 |
||
341 |
FontContainer fontContainer = TextEditorProperties.FontContainer; |
|
342 |
foreach (TextWord word in line.Words) { |
|
343 |
switch (word.Type) { |
|
344 |
case TextWordType.Space: |
|
345 |
Advance(ref xPos, ref yPos, margin.Width, primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight); |
|
346 |
// if (!gotNonWhitespace) { |
|
347 |
// curTabIndent = xPos; |
|
348 |
// } |
|
349 |
break; |
|
350 |
case TextWordType.Tab: |
|
351 |
Advance(ref xPos, ref yPos, margin.Width, TabIndent * primaryTextArea.TextArea.TextView.WideSpaceWidth, fontHeight); |
|
352 |
// if (!gotNonWhitespace) { |
|
353 |
// curTabIndent = xPos; |
|
354 |
// } |
|
355 |
break; |
|
356 |
case TextWordType.Word: |
|
357 |
// if (!gotNonWhitespace) { |
|
358 |
// gotNonWhitespace = true; |
|
359 |
// curTabIndent += TabIndent * primaryTextArea.TextArea.TextView.GetWidth(' '); |
|
360 |
// } |
|
361 |
g.DrawString(word.Word, word.GetFont(fontContainer), BrushRegistry.GetBrush(word.Color), xPos + margin.X, yPos); |
|
362 |
SizeF drawingSize = g.MeasureString(word.Word, word.GetFont(fontContainer), new SizeF(margin.Width, fontHeight * 100), printingStringFormat); |
|
363 |
Advance(ref xPos, ref yPos, margin.Width, drawingSize.Width, fontHeight); |
|
364 |
break; |
|
365 |
} |
|
366 |
} |
|
367 |
} |
|
368 |
||
369 |
void PrintPage(object sender, PrintPageEventArgs ev) |
|
370 |
{ |
|
371 |
Graphics g = ev.Graphics; |
|
372 |
float yPos = ev.MarginBounds.Top; |
|
373 |
||
374 |
while (curLineNr < Document.TotalNumberOfLines) { |
|
375 |
LineSegment curLine = Document.GetLineSegment(curLineNr); |
|
376 |
if (curLine.Words != null) { |
|
377 |
float drawingHeight = MeasurePrintingHeight(g, curLine, ev.MarginBounds.Width); |
|
378 |
if (drawingHeight + yPos > ev.MarginBounds.Bottom) { |
|
379 |
break; |
|
380 |
} |
|
381 |
||
382 |
DrawLine(g, curLine, yPos, ev.MarginBounds); |
|
383 |
yPos += drawingHeight; |
|
384 |
} |
|
385 |
++curLineNr; |
|
386 |
} |
|
387 |
||
388 |
// If more lines exist, print another page. |
|
389 |
ev.HasMorePages = curLineNr < Document.TotalNumberOfLines; |
|
390 |
} |
|
391 |
#endregion |
|
392 |
} |
|
393 |
} |