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
}