Code Coverage Statistics for Source File

c:\Tools\SD3\src\Libraries\ICSharpCode.TextEditor\Project\Src\Gui\CompletionWindow\CodeCompletionWindow.cs

Sequence Point Coverage
N/A
0 of 0
Branch Coverage
N/A
0 of 0
Lines
295
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: 2533 $</version>
6
// </file>
7
8
using System;
9
using System.Drawing;
10
using System.Diagnostics;
11
using System.Windows.Forms;
12
using ICSharpCode.TextEditor.Document;
13
14
namespace ICSharpCode.TextEditor.Gui.CompletionWindow
15
{
16
	public class CodeCompletionWindow : AbstractCompletionWindow
17
	{
18
		ICompletionData[] completionData;
19
		CodeCompletionListView   codeCompletionListView;
20
		VScrollBar    vScrollBar = new VScrollBar();
21
		ICompletionDataProvider dataProvider;
22
		IDocument document;
23
		
24
		int                      startOffset;
25
		int                      endOffset;
26
		DeclarationViewWindow    declarationViewWindow = null;
27
		Rectangle workingScreen;
28
		
29
		public static CodeCompletionWindow ShowCompletionWindow(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider, char firstChar)
30
		{
31
			ICompletionData[] completionData = completionDataProvider.GenerateCompletionData(fileName, control.ActiveTextAreaControl.TextArea, firstChar);
32
			if (completionData == null || completionData.Length == 0) {
33
				return null;
34
			}
35
			CodeCompletionWindow codeCompletionWindow = new CodeCompletionWindow(completionDataProvider, completionData, parent, control);
36
			codeCompletionWindow.ShowCompletionWindow();
37
			return codeCompletionWindow;
38
		}
39
		
40
		CodeCompletionWindow(ICompletionDataProvider completionDataProvider, ICompletionData[] completionData, Form parentForm, TextEditorControl control) : base(parentForm, control)
41
		{
42
			this.dataProvider = completionDataProvider;
43
			this.completionData = completionData;
44
			this.document = control.Document;
45
			
46
			workingScreen = Screen.GetWorkingArea(Location);
47
			startOffset = control.ActiveTextAreaControl.Caret.Offset + 1;
48
			endOffset   = startOffset;
49
			if (completionDataProvider.PreSelection != null) {
50
				startOffset -= completionDataProvider.PreSelection.Length + 1;
51
				endOffset--;
52
			}
53
			
54
			codeCompletionListView = new CodeCompletionListView(completionData);
55
			codeCompletionListView.ImageList = completionDataProvider.ImageList;
56
			codeCompletionListView.Dock = DockStyle.Fill;
57
			codeCompletionListView.SelectedItemChanged += new EventHandler(CodeCompletionListViewSelectedItemChanged);
58
			codeCompletionListView.DoubleClick += new EventHandler(CodeCompletionListViewDoubleClick);
59
			codeCompletionListView.Click  += new EventHandler(CodeCompletionListViewClick);
60
			Controls.Add(codeCompletionListView);
61
			
62
			const int MaxListLength = 10;
63
			if (completionData.Length > MaxListLength) {
64
				vScrollBar.Dock = DockStyle.Right;
65
				vScrollBar.Minimum = 0;
66
				vScrollBar.Maximum = completionData.Length - 1;
67
				vScrollBar.SmallChange = 1;
68
				vScrollBar.LargeChange = MaxListLength;
69
				codeCompletionListView.FirstItemChanged += new EventHandler(CodeCompletionListViewFirstItemChanged);
70
				Controls.Add(vScrollBar);
71
			}
72
			
73
			this.drawingSize = new Size(codeCompletionListView.ItemHeight * 10,
74
			                            codeCompletionListView.ItemHeight * Math.Min(MaxListLength, completionData.Length));
75
			SetLocation();
76
			
77
			if (declarationViewWindow == null) {
78
				declarationViewWindow = new DeclarationViewWindow(parentForm);
79
			}
80
			SetDeclarationViewLocation();
81
			declarationViewWindow.ShowDeclarationViewWindow();
82
			declarationViewWindow.MouseMove += ControlMouseMove;
83
			control.Focus();
84
			CodeCompletionListViewSelectedItemChanged(this, EventArgs.Empty);
85
			
86
			if (completionDataProvider.DefaultIndex >= 0) {
87
				codeCompletionListView.SelectIndex(completionDataProvider.DefaultIndex);
88
			}
89
			
90
			if (completionDataProvider.PreSelection != null) {
91
				CaretOffsetChanged(this, EventArgs.Empty);
92
			}
93
			
94
			vScrollBar.ValueChanged += VScrollBarValueChanged;
95
			document.DocumentAboutToBeChanged += DocumentAboutToBeChanged;
96
		}
97
		
98
		bool inScrollUpdate;
99
		
100
		void CodeCompletionListViewFirstItemChanged(object sender, EventArgs e)
101
		{
102
			if (inScrollUpdate) return;
103
			inScrollUpdate = true;
104
			vScrollBar.Value = Math.Min(vScrollBar.Maximum, codeCompletionListView.FirstItem);
105
			inScrollUpdate = false;
106
		}
107
		
108
		void VScrollBarValueChanged(object sender, EventArgs e)
109
		{
110
			if (inScrollUpdate) return;
111
			inScrollUpdate = true;
112
			codeCompletionListView.FirstItem = vScrollBar.Value;
113
			codeCompletionListView.Refresh();
114
			control.ActiveTextAreaControl.TextArea.Focus();
115
			inScrollUpdate = false;
116
		}
117
		
118
		void SetDeclarationViewLocation()
119
		{
120
			//  This method uses the side with more free space
121
			int leftSpace = Bounds.Left - workingScreen.Left;
122
			int rightSpace = workingScreen.Right - Bounds.Right;
123
			Point pos;
124
			// The declaration view window has better line break when used on
125
			// the right side, so prefer the right side to the left.
126
			if (rightSpace * 2 > leftSpace)
127
				pos = new Point(Bounds.Right, Bounds.Top);
128
			else
129
				pos = new Point(Bounds.Left - declarationViewWindow.Width, Bounds.Top);
130
			if (declarationViewWindow.Location != pos) {
131
				declarationViewWindow.Location = pos;
132
			}
133
		}
134
		
135
		protected override void SetLocation()
136
		{
137
			base.SetLocation();
138
			if (declarationViewWindow != null) {
139
				SetDeclarationViewLocation();
140
			}
141
		}
142
		
143
		public void HandleMouseWheel(MouseEventArgs e)
144
		{
145
			int MAX_DELTA  = 120; // basically it's constant now, but could be changed later by MS
146
			int multiplier = e.Delta / MAX_DELTA;
147
			multiplier *= System.Windows.Forms.SystemInformation.MouseWheelScrollLines * vScrollBar.SmallChange;
148
			
149
			int newValue;
150
			if (System.Windows.Forms.SystemInformation.MouseWheelScrollLines > 0) {
151
				newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * multiplier;
152
			} else {
153
				newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * multiplier;
154
			}
155
			vScrollBar.Value = Math.Max(vScrollBar.Minimum, Math.Min(vScrollBar.Maximum - vScrollBar.LargeChange + 1, newValue));
156
		}
157
158
		void CodeCompletionListViewSelectedItemChanged(object sender, EventArgs e)
159
		{
160
			ICompletionData data = codeCompletionListView.SelectedCompletionData;
161
			if (data != null && data.Description != null && data.Description.Length > 0) {
162
				declarationViewWindow.Description = data.Description;
163
				SetDeclarationViewLocation();
164
			} else {
165
				declarationViewWindow.Description = null;
166
			}
167
		}
168
		
169
		public override bool ProcessKeyEvent(char ch)
170
		{
171
			switch (dataProvider.ProcessKey(ch)) {
172
				case CompletionDataProviderKeyResult.BeforeStartKey:
173
					// increment start+end, then process as normal char
174
					++startOffset;
175
					++endOffset;
176
					return base.ProcessKeyEvent(ch);
177
				case CompletionDataProviderKeyResult.NormalKey:
178
					// just process normally
179
					return base.ProcessKeyEvent(ch);
180
				case CompletionDataProviderKeyResult.InsertionKey:
181
					return InsertSelectedItem(ch);
182
				default:
183
					throw new InvalidOperationException("Invalid return value of dataProvider.ProcessKey");
184
			}
185
		}
186
		
187
		void DocumentAboutToBeChanged(object sender, DocumentEventArgs e)
188
		{
189
			// => startOffset test required so that this startOffset/endOffset are not incremented again
190
			//    for BeforeStartKey characters
191
			if (e.Offset >= startOffset && e.Offset <= endOffset) {
192
				if (e.Length > 0) { // length of removed region
193
					endOffset -= e.Length;
194
				}
195
				if (!string.IsNullOrEmpty(e.Text)) {
196
					endOffset += e.Text.Length;
197
				}
198
			}
199
		}
200
		
201
		protected override void CaretOffsetChanged(object sender, EventArgs e)
202
		{
203
			int offset = control.ActiveTextAreaControl.Caret.Offset;
204
			if (offset == startOffset) {
205
				return;
206
			}
207
			if (offset < startOffset || offset > endOffset) {
208
				Close();
209
			} else {
210
				codeCompletionListView.SelectItemWithStart(control.Document.GetText(startOffset, offset - startOffset));
211
			}
212
		}
213
		
214
		protected override bool ProcessTextAreaKey(Keys keyData)
215
		{
216
			if (!Visible) {
217
				return false;
218
			}
219
			
220
			switch (keyData) {
221
				case Keys.Home:
222
					codeCompletionListView.SelectIndex(0);
223
					return true;
224
				case Keys.End:
225
					codeCompletionListView.SelectIndex(completionData.Length-1);
226
					return true;
227
				case Keys.PageDown:
228
					codeCompletionListView.PageDown();
229
					return true;
230
				case Keys.PageUp:
231
					codeCompletionListView.PageUp();
232
					return true;
233
				case Keys.Down:
234
					codeCompletionListView.SelectNextItem();
235
					return true;
236
				case Keys.Up:
237
					codeCompletionListView.SelectPrevItem();
238
					return true;
239
				case Keys.Tab:
240
				case Keys.Return:
241
					InsertSelectedItem('\0');
242
					return true;
243
			}
244
			return base.ProcessTextAreaKey(keyData);
245
		}
246
		
247
		void CodeCompletionListViewDoubleClick(object sender, EventArgs e)
248
		{
249
			InsertSelectedItem('\0');
250
		}
251
		
252
		void CodeCompletionListViewClick(object sender, EventArgs e)
253
		{
254
			control.ActiveTextAreaControl.TextArea.Focus();
255
		}
256
		
257
		protected override void Dispose(bool disposing)
258
		{
259
			if (disposing) {
260
				document.DocumentAboutToBeChanged -= DocumentAboutToBeChanged;
261
				if (codeCompletionListView != null) {
262
					codeCompletionListView.Dispose();
263
					codeCompletionListView = null;
264
				}
265
				if (declarationViewWindow != null) {
266
					declarationViewWindow.Dispose();
267
					declarationViewWindow = null;
268
				}
269
			}
270
			base.Dispose(disposing);
271
		}
272
		
273
		bool InsertSelectedItem(char ch)
274
		{
275
			document.DocumentAboutToBeChanged -= DocumentAboutToBeChanged;
276
			ICompletionData data = codeCompletionListView.SelectedCompletionData;
277
			bool result = false;
278
			if (data != null) {
279
				control.BeginUpdate();
280
				
281
				try {
282
					if (endOffset - startOffset > 0) {
283
						control.Document.Remove(startOffset, endOffset - startOffset);
284
					}
285
					Debug.Assert(startOffset <= document.TextLength);
286
					result = dataProvider.InsertAction(data, control.ActiveTextAreaControl.TextArea, startOffset, ch);
287
				} finally {
288
					control.EndUpdate();
289
				}
290
			}
291
			Close();
292
			return result;
293
		}
294
	}
295
}