// // // // // $Revision: 2533 $ // using System; using System.Drawing; using System.Diagnostics; using System.Windows.Forms; using ICSharpCode.TextEditor.Document; namespace ICSharpCode.TextEditor.Gui.CompletionWindow { public class PABCNETCodeCompletionWindow : AbstractCompletionWindow { ICompletionData[] completionData; PABCNETCodeCompletionListView codeCompletionListView; VScrollBar vScrollBar = new VScrollBar(); ICompletionDataProvider dataProvider; IDocument document; private bool _is_overrided_meths = false; public bool is_overrided_meths { get { return _is_overrided_meths; } set { _is_overrided_meths = value; if (value && completionData != null) CalcFormWidth(); } } int startOffset; int endOffset; DeclarationWindow declarationViewWindow = null; Rectangle workingScreen; Point lastCursorScreenPosition; public static PABCNETCodeCompletionWindow ShowCompletionWindow(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider, char firstChar, bool visibleKeyPressed, bool is_by_dot,PascalABCCompiler.Parsers.KeywordKind keyw) { ICompletionData[] completionData = (completionDataProvider as VisualPascalABC.CodeCompletionProvider).GenerateCompletionDataWithKeyword(fileName, control.ActiveTextAreaControl.TextArea, firstChar, keyw); if (completionData == null || completionData.Length == 0) { return null; } PABCNETCodeCompletionWindow codeCompletionWindow = new PABCNETCodeCompletionWindow(completionDataProvider, completionData, parent, control, visibleKeyPressed, is_by_dot); codeCompletionWindow.ShowCompletionWindow(); return codeCompletionWindow; } public static PABCNETCodeCompletionWindow ShowOverridableMethodsCompletionWindows(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider) { ICompletionData[] completionData = (completionDataProvider as VisualPascalABC.CodeCompletionProvider).GenerateCompletionDataForOverridableMethods(fileName, control.ActiveTextAreaControl.TextArea); if (completionData == null || completionData.Length == 0) { return null; } PABCNETCodeCompletionWindow codeCompletionWindow = new PABCNETCodeCompletionWindow(completionDataProvider, completionData, parent, control, false, false); codeCompletionWindow.is_overrided_meths = true; codeCompletionWindow.ShowCompletionWindow(); return codeCompletionWindow; } public void CalcFormWidth() { this.codeCompletionListView.CalcWidth(); } public static PABCNETCodeCompletionWindow ShowCompletionWindowWithFirstChar(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider, char firstChar, PascalABCCompiler.Parsers.KeywordKind keyw) { ICompletionData[] completionData = (completionDataProvider as VisualPascalABC.CodeCompletionProvider).GenerateCompletionDataByFirstChar(fileName, control.ActiveTextAreaControl.TextArea, firstChar, keyw); if (completionData == null || completionData.Length == 0) { return null; } (completionDataProvider as VisualPascalABC.CodeCompletionProvider).preSelection = firstChar.ToString(); PABCNETCodeCompletionWindow codeCompletionWindow = new PABCNETCodeCompletionWindow(completionDataProvider, completionData, parent, control, true, false); codeCompletionWindow.ShowCompletionWindow(); return codeCompletionWindow; } PABCNETCodeCompletionWindow(ICompletionDataProvider completionDataProvider, ICompletionData[] completionData, Form parentForm, TextEditorControl control,bool visibleKeyPressed, bool is_by_dot) : base(parentForm, control) { this.dataProvider = completionDataProvider; this.completionData = completionData; this.document = control.Document; workingScreen = Screen.GetWorkingArea(Location); lastCursorScreenPosition = control.ActiveTextAreaControl.Caret.ScreenPosition; startOffset = control.ActiveTextAreaControl.Caret.Offset + (visibleKeyPressed ? 1 : 0); endOffset = startOffset; if (completionDataProvider.PreSelection != null) { startOffset -= completionDataProvider.PreSelection.Length; //+ 1; if (visibleKeyPressed) endOffset--; //endOffset--; (completionDataProvider as VisualPascalABC.CodeCompletionProvider).preSelection = null; } codeCompletionListView = new PABCNETCodeCompletionListView(completionData, is_by_dot); codeCompletionListView.ImageList = completionDataProvider.ImageList; codeCompletionListView.Dock = DockStyle.Fill; codeCompletionListView.SelectedItemChanged += new EventHandler(CodeCompletionListViewSelectedItemChanged); codeCompletionListView.DoubleClick += new EventHandler(CodeCompletionListViewDoubleClick); codeCompletionListView.Click += new EventHandler(CodeCompletionListViewClick); codeCompletionListView.Font = new Font(VisualPascalABC.Constants.CompletionWindowCodeCompletionListViewFontName,codeCompletionListView.Font.Size); Controls.Add(codeCompletionListView); int MaxListLength = VisualPascalABC.Constants.CompletionWindowMaxListLength; if (completionData.Length > MaxListLength) { vScrollBar.Dock = DockStyle.Right; vScrollBar.Minimum = 0; vScrollBar.Maximum = completionData.Length - 1; vScrollBar.SmallChange = 1; vScrollBar.LargeChange = MaxListLength; codeCompletionListView.FirstItemChanged += new EventHandler(CodeCompletionListViewFirstItemChanged); Controls.Add(vScrollBar); } this.drawingSize = new Size(//codeCompletionListView.ItemHeight * 10, VisualPascalABC.Constants.CompletionWindowWidth, codeCompletionListView.ItemHeight * Math.Min(MaxListLength, completionData.Length) + 2); SetLocation(); if (declarationViewWindow == null) { declarationViewWindow = new DeclarationWindow(parentForm); declarationViewWindow.in_completion_list = true; declarationViewWindow.Font = new Font(VisualPascalABC.Constants.CompletionWindowDeclarationViewWindowFontName, declarationViewWindow.Font.Size); } SetDeclarationViewLocation(); //DS закоментил, это желтый квадрат при старте //declarationViewWindow.ShowDeclarationViewWindow(); declarationViewWindow.MouseMove += ControlMouseMove; control.Focus(); CodeCompletionListViewSelectedItemChanged(this, EventArgs.Empty); if ((completionDataProvider as VisualPascalABC.CodeCompletionProvider).DefaultCompletionElement != null) { if ((completionDataProvider as VisualPascalABC.CodeCompletionProvider).ByFirstChar) codeCompletionListView.FirstInsert = true; codeCompletionListView.SelectIndexByCompletionData((completionDataProvider as VisualPascalABC.CodeCompletionProvider).DefaultCompletionElement); } if (completionDataProvider.PreSelection != null) { CaretOffsetChanged(this, EventArgs.Empty); } vScrollBar.ValueChanged += VScrollBarValueChanged; document.DocumentAboutToBeChanged += DocumentAboutToBeChanged; } bool inScrollUpdate; void CodeCompletionListViewFirstItemChanged(object sender, EventArgs e) { if (inScrollUpdate) return; inScrollUpdate = true; vScrollBar.Value = Math.Min(vScrollBar.Maximum, codeCompletionListView.FirstItem); inScrollUpdate = false; } void VScrollBarValueChanged(object sender, EventArgs e) { if (inScrollUpdate) return; inScrollUpdate = true; codeCompletionListView.FirstItem = vScrollBar.Value; codeCompletionListView.Refresh(); control.ActiveTextAreaControl.TextArea.Focus(); inScrollUpdate = false; } void SetDeclarationViewLocation() { // This method uses the side with more free space int leftSpace = Bounds.Left - workingScreen.Left; int rightSpace = workingScreen.Right - Bounds.Right; Point pos; // The declaration view window has better line break when used on // the right side, so prefer the right side to the left. if (rightSpace * 2 > leftSpace) pos = new Point(Bounds.Right+2, Bounds.Top); else pos = new Point(Bounds.Left - declarationViewWindow.Width+2, Bounds.Top); if (declarationViewWindow.Location != pos) { declarationViewWindow.Location = pos; } } protected override void SetLocation() { base.SetLocation(); if (declarationViewWindow != null) { SetDeclarationViewLocation(); } } public void HandleMouseWheel(MouseEventArgs e) { int MAX_DELTA = 120; // basically it's constant now, but could be changed later by MS int multiplier = e.Delta / MAX_DELTA; multiplier *= System.Windows.Forms.SystemInformation.MouseWheelScrollLines * vScrollBar.SmallChange; int newValue; if (System.Windows.Forms.SystemInformation.MouseWheelScrollLines > 0) { newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * multiplier; } else { newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * multiplier; } vScrollBar.Value = Math.Max(vScrollBar.Minimum, Math.Min(vScrollBar.Maximum - vScrollBar.LargeChange + 1, newValue)); } void CodeCompletionListViewSelectedItemChanged(object sender, EventArgs e) { ICompletionData data = codeCompletionListView.SelectedCompletionData; if (data != null && !(data as UserDefaultCompletionData).IsOnOverrideWindow && data.Description != null && data.Description.Length > 0) { declarationViewWindow.Description = data.Description; SetDeclarationViewLocation(); } else { declarationViewWindow.Description = null; } } public override bool ProcessKeyEvent(char ch) { switch (dataProvider.ProcessKey(ch)) { case CompletionDataProviderKeyResult.BeforeStartKey: // increment start+end, then process as normal char ++startOffset; ++endOffset; return base.ProcessKeyEvent(ch); case CompletionDataProviderKeyResult.NormalKey: // just process normally if (ch == '_') { Close(); return true; } return base.ProcessKeyEvent(ch); case CompletionDataProviderKeyResult.InsertionKey: return InsertSelectedItem(ch); default: throw new InvalidOperationException("Invalid return value of dataProvider.ProcessKey"); } } void DocumentAboutToBeChanged(object sender, DocumentEventArgs e) { // => startOffset test required so that this startOffset/endOffset are not incremented again // for BeforeStartKey characters if (e.Offset >= startOffset && e.Offset <= endOffset) { if (e.Length > 0) { // length of removed region endOffset -= e.Length; } if (!string.IsNullOrEmpty(e.Text)) { endOffset += e.Text.Length; } } } void fiexerrorTextAreaInvalidate() { //Исправление глюка с остающимся курсором если нажать ескейп. //В новой версии редактора должны исправить, надо убрать это. Rectangle r = new Rectangle(lastCursorScreenPosition, new Size(control.ActiveTextAreaControl.TextArea.Font.Height, control.ActiveTextAreaControl.TextArea.Font.Height + 3)); control.ActiveTextAreaControl.TextArea.Invalidate(r); } protected override void CaretOffsetChanged(object sender, EventArgs e) { int offset = control.ActiveTextAreaControl.Caret.Offset; if (offset == startOffset) { return; } if (offset < startOffset || offset > endOffset) { Close(); fiexerrorTextAreaInvalidate(); } else { codeCompletionListView.SelectItemWithStart(control.Document.GetText(startOffset, offset - startOffset)); } lastCursorScreenPosition = control.ActiveTextAreaControl.TextArea.Caret.ScreenPosition; } protected override bool ProcessTextAreaKey(Keys keyData) { if (!Visible) { return false; } switch (keyData) { case Keys.Home: codeCompletionListView.SelectIndex(0); return true; case Keys.End: codeCompletionListView.SelectIndex(completionData.Length-1); return true; case Keys.PageDown: codeCompletionListView.PageDown(); return true; case Keys.PageUp: codeCompletionListView.PageUp(); return true; case Keys.Down: codeCompletionListView.SelectNextItem(); return true; case Keys.Up: codeCompletionListView.SelectPrevItem(); return true; case Keys.Tab: case Keys.Return: InsertSelectedItem('\0'); return true; case Keys.Escape: fiexerrorTextAreaInvalidate(); break; } return base.ProcessTextAreaKey(keyData); } void CodeCompletionListViewDoubleClick(object sender, EventArgs e) { InsertSelectedItem('\0'); } void CodeCompletionListViewClick(object sender, EventArgs e) { control.ActiveTextAreaControl.TextArea.Focus(); } protected override void Dispose(bool disposing) { if (disposing) { document.DocumentAboutToBeChanged -= DocumentAboutToBeChanged; if (codeCompletionListView != null) { codeCompletionListView.Dispose(); codeCompletionListView = null; } if (declarationViewWindow != null) { declarationViewWindow.Dispose(); declarationViewWindow = null; } } base.Dispose(disposing); } public void SelectIndex(int num) { if (codeCompletionListView != null) codeCompletionListView.SelectIndex(num); } bool InsertSelectedItem(char ch) { document.DocumentAboutToBeChanged -= DocumentAboutToBeChanged; ICompletionData data = codeCompletionListView.SelectedCompletionData; if (VisualPascalABC.VisualPABCSingleton.MainForm.UserOptions.EnableSmartIntellisense) { VisualPascalABC.CompletionDataDispatcher.AddLastUsedItem(data); VisualPascalABC.CompletionDataDispatcher.BindMember(data); } bool result = false; if (data != null) { control.BeginUpdate(); try { if (endOffset - startOffset > 0) { control.Document.Remove(startOffset, endOffset - startOffset); } Debug.Assert(startOffset <= document.TextLength); result = dataProvider.InsertAction(data, control.ActiveTextAreaControl.TextArea, startOffset, ch); } finally { control.EndUpdate(); } } Close(); return result; } } }