pascalabcnet/VisualPascalABCNET/DS/CodeCompletionVisual/CodeCompletionWindow.cs
Бондарев Иван b99f7f7856 bug fix #706
2018-03-07 21:37:47 +01:00

378 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision: 2533 $</version>
// </file>
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
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;
}
}
}