Browse Source

XML editor now uses the text editor's CodeCompletionWindow instead of its own custom version.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2760 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 18 years ago
parent
commit
849b934739
  1. 305
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/CodeCompletionWindow.cs
  2. 12
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionDataProvider.cs
  3. 3
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlEditorControl.cs
  4. 3
      src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj
  5. 2
      src/AddIns/DisplayBindings/XmlEditor/Test/Completion/FirstCompletionListItemSelectedTestFixture.cs
  6. 53
      src/AddIns/DisplayBindings/XmlEditor/Test/Completion/ProcessKeyTests.cs
  7. 1
      src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj
  8. 73
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/CompletionWindow/CodeCompletionWindow.cs

305
src/AddIns/DisplayBindings/XmlEditor/Project/Src/CodeCompletionWindow.cs

@ -1,305 +0,0 @@ @@ -1,305 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Drawing;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
namespace ICSharpCode.XmlEditor
{
public class CodeCompletionWindow : AbstractCompletionWindow
{
static ICompletionData[] completionData;
CodeCompletionListView codeCompletionListView;
VScrollBar vScrollBar = new VScrollBar();
int startOffset;
int endOffset;
DeclarationViewWindow declarationViewWindow = null;
Rectangle workingScreen;
const int ScrollbarWidth = 16;
bool showDeclarationWindow = true;
public static CodeCompletionWindow ShowCompletionWindow(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider, char firstChar)
{
return ShowCompletionWindow(parent, control, fileName, completionDataProvider, firstChar, true);
}
public static CodeCompletionWindow ShowCompletionWindow(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider, char firstChar, bool showDeclarationWindow)
{
completionData = completionDataProvider.GenerateCompletionData(fileName, control.ActiveTextAreaControl.TextArea, firstChar);
if (completionData == null || completionData.Length == 0) {
return null;
}
CodeCompletionWindow codeCompletionWindow = new CodeCompletionWindow(completionDataProvider, parent, control, fileName, showDeclarationWindow);
codeCompletionWindow.ShowCompletionWindow();
return codeCompletionWindow;
}
CodeCompletionWindow(ICompletionDataProvider completionDataProvider, Form parentForm, TextEditorControl control, string fileName, bool showDeclarationWindow) : base(parentForm, control)
{
this.showDeclarationWindow = showDeclarationWindow;
workingScreen = Screen.GetWorkingArea(Location);
startOffset = control.ActiveTextAreaControl.Caret.Offset + 1;
endOffset = startOffset;
if (completionDataProvider.PreSelection != null) {
startOffset -= completionDataProvider.PreSelection.Length + 1;
endOffset--;
}
codeCompletionListView = new CodeCompletionListView(completionData);
codeCompletionListView.ImageList = completionDataProvider.ImageList;
codeCompletionListView.Dock = DockStyle.Fill;
codeCompletionListView.SelectedItemChanged += new EventHandler(CodeCompletionListViewSelectedItemChanged);
codeCompletionListView.DoubleClick += new EventHandler(CodeCompletionListViewDoubleClick);
codeCompletionListView.Click += new EventHandler(CodeCompletionListViewClick);
Controls.Add(codeCompletionListView);
if (completionData.Length > 10) {
vScrollBar.Dock = DockStyle.Right;
vScrollBar.Minimum = 0;
vScrollBar.Maximum = completionData.Length - 8;
vScrollBar.SmallChange = 1;
vScrollBar.LargeChange = 3;
codeCompletionListView.FirstItemChanged += new EventHandler(CodeCompletionListViewFirstItemChanged);
Controls.Add(vScrollBar);
}
this.drawingSize = GetListViewSize();
SetLocation();
declarationViewWindow = new DeclarationViewWindow(parentForm);
SetDeclarationViewLocation();
declarationViewWindow.MouseMove += ControlMouseMove;
declarationViewWindow.ShowDeclarationViewWindow();
control.Focus();
CodeCompletionListViewSelectedItemChanged(this, EventArgs.Empty);
int defaultIndex = completionDataProvider.DefaultIndex;
if (defaultIndex >= 0) {
codeCompletionListView.SelectIndex(defaultIndex);
codeCompletionListView.CenterViewOn(defaultIndex);
}
if (completionDataProvider.PreSelection != null) {
CaretOffsetChanged(this, EventArgs.Empty);
}
vScrollBar.Scroll += new ScrollEventHandler(DoScroll);
}
public void HandleMouseWheel(MouseEventArgs e)
{
int MAX_DELTA = 120; // basically it's constant now, but could be changed later by MS
int multiplier = Math.Abs(e.Delta) / MAX_DELTA;
int newValue;
if (System.Windows.Forms.SystemInformation.MouseWheelScrollLines > 0) {
newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * Math.Sign(e.Delta) * System.Windows.Forms.SystemInformation.MouseWheelScrollLines * vScrollBar.SmallChange * multiplier;
} else {
newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * Math.Sign(e.Delta) * vScrollBar.LargeChange;
}
vScrollBar.Value = Math.Max(vScrollBar.Minimum, Math.Min(vScrollBar.Maximum, newValue));
DoScroll(this, null);
}
void CodeCompletionListViewFirstItemChanged(object sender, EventArgs e)
{
vScrollBar.Value = Math.Min(vScrollBar.Maximum, codeCompletionListView.FirstItem);
}
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, Bounds.Top);
else
pos = new Point(Bounds.Left - declarationViewWindow.Width, Bounds.Top);
if (declarationViewWindow.Location != pos) {
declarationViewWindow.Location = pos;
}
}
protected override void SetLocation()
{
base.SetLocation();
if (declarationViewWindow != null) {
SetDeclarationViewLocation();
}
}
void CodeCompletionListViewSelectedItemChanged(object sender, EventArgs e)
{
ICompletionData data = codeCompletionListView.SelectedCompletionData;
if (data != null && data.Description != null && showDeclarationWindow) {
declarationViewWindow.Description = data.Description;
SetDeclarationViewLocation();
} else {
declarationViewWindow.Size = new Size(0, 0);
}
}
public override bool ProcessKeyEvent(char ch)
{
if (XmlParser.IsXmlNameChar(ch) || XmlParser.IsAttributeValueChar(ch)){
++endOffset;
return base.ProcessKeyEvent(ch);
}
return false;
}
protected override void CaretOffsetChanged(object sender, EventArgs e)
{
int offset = control.ActiveTextAreaControl.Caret.Offset;
if (offset < startOffset || offset > endOffset) {
Close();
} else {
codeCompletionListView.SelectItemWithStart(control.Document.GetText(startOffset, offset - startOffset));
}
}
protected void DoScroll(object sender, ScrollEventArgs sea)
{
codeCompletionListView.FirstItem = vScrollBar.Value;
codeCompletionListView.Refresh();
control.ActiveTextAreaControl.TextArea.Focus();
}
protected override bool ProcessTextAreaKey(Keys keyData)
{
if (!Visible) {
return false;
}
switch (keyData) {
case Keys.Back:
--endOffset;
if (endOffset < startOffset) {
Close();
}
return false;
case Keys.Delete:
if (control.ActiveTextAreaControl.Caret.Offset <= endOffset) {
--endOffset;
}
if (endOffset < startOffset) {
Close();
}
return false;
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();
return true;
}
return base.ProcessTextAreaKey(keyData);
}
void CodeCompletionListViewDoubleClick(object sender, EventArgs e)
{
InsertSelectedItem();
}
void CodeCompletionListViewClick(object sender, EventArgs e)
{
control.ActiveTextAreaControl.TextArea.Focus();
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Dispose();
codeCompletionListView.Dispose();
codeCompletionListView = null;
declarationViewWindow.Dispose();
declarationViewWindow = null;
}
void InsertSelectedItem()
{
ICompletionData data = codeCompletionListView.SelectedCompletionData;
if (data != null) {
control.BeginUpdate();
if (endOffset - startOffset > 0) {
control.Document.Remove(startOffset, endOffset - startOffset);
control.ActiveTextAreaControl.Caret.Position = control.Document.OffsetToPosition(startOffset);
}
data.InsertAction(control.ActiveTextAreaControl.TextArea, '\0');
control.EndUpdate();
}
Close();
}
Size GetListViewSize()
{
int height = codeCompletionListView.ItemHeight * Math.Min(10, completionData.Length);
int width = GetListViewWidth(codeCompletionListView.ItemHeight * 10, height);
return new Size(width, height);
}
/// <summary>
/// Gets the list view width large enough to handle the longest completion data
/// text string.
/// </summary>
/// <param name="defaultWidth">The default width of the list view.</param>
/// <param name="height">The height of the list view. This is
/// used to determine if the scrollbar is visible.</param>
/// <returns>The list view width to accommodate the longest completion
/// data text string; otherwise the default width.</returns>
int GetListViewWidth(int defaultWidth, int height)
{
Graphics graphics = codeCompletionListView.CreateGraphics();
float width = defaultWidth;
for(int i = 0; i < completionData.Length; ++i)
{
float itemWidth = graphics.MeasureString(completionData[i].Text.ToString(), codeCompletionListView.Font).Width;
if(itemWidth > width) {
width = itemWidth;
}
}
graphics.Dispose();
float totalItemsHeight = codeCompletionListView.ItemHeight * completionData.Length;
if (totalItemsHeight > height) {
width += ScrollbarWidth; // Compensate for scroll bar.
}
return (int)width;
}
}
}

12
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionDataProvider.cs

@ -36,6 +36,18 @@ namespace ICSharpCode.XmlEditor @@ -36,6 +36,18 @@ namespace ICSharpCode.XmlEditor
return XmlCompletionDataImageList.GetImageList();
}
}
/// <summary>
/// Overrides the default behaviour and allows special xml
/// characters such as '.' and ':' to be used as completion data.
/// </summary>
public override CompletionDataProviderKeyResult ProcessKey(char key)
{
if (key == '\r' || key == '\t') {
return CompletionDataProviderKeyResult.InsertionKey;
}
return CompletionDataProviderKeyResult.NormalKey;
}
public override ICompletionData[] GenerateCompletionData(string fileName, TextArea textArea, char charTyped)
{

3
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlEditorControl.cs

@ -15,6 +15,7 @@ using ICSharpCode.SharpDevelop.Gui; @@ -15,6 +15,7 @@ using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Actions;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
namespace ICSharpCode.XmlEditor
{
@ -221,7 +222,7 @@ namespace ICSharpCode.XmlEditor @@ -221,7 +222,7 @@ namespace ICSharpCode.XmlEditor
if (IsCodeCompletionEnabled) {
XmlCompletionDataProvider completionDataProvider = new XmlCompletionDataProvider(schemaCompletionDataItems, defaultSchemaCompletionData, defaultNamespacePrefix);
codeCompletionWindow = CodeCompletionWindow.ShowCompletionWindow(ParentForm, this, FileName, completionDataProvider, ch, XmlEditorAddInOptions.ShowSchemaAnnotation);
codeCompletionWindow = CodeCompletionWindow.ShowCompletionWindow(ParentForm, this, FileName, completionDataProvider, ch, XmlEditorAddInOptions.ShowSchemaAnnotation, false);
if (codeCompletionWindow != null) {
codeCompletionWindow.Closed += new EventHandler(CodeCompletionWindowClosed);

3
src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj

@ -88,9 +88,6 @@ @@ -88,9 +88,6 @@
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Src\XmlSchemaListBoxItem.cs" />
<Compile Include="Src\CodeCompletionWindow.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Src\XmlEditorAddInOptions.cs" />
<Compile Include="Src\SelectXmlSchemaForm.cs">
<SubType>Form</SubType>

2
src/AddIns/DisplayBindings/XmlEditor/Test/Completion/FirstCompletionListItemSelectedTestFixture.cs

@ -42,7 +42,7 @@ namespace XmlEditor.Tests.Completion @@ -42,7 +42,7 @@ namespace XmlEditor.Tests.Completion
provider = new XmlCompletionDataProvider(schemas, schema, String.Empty);
TextEditorControl textEditor = new TextEditorControl();
completionDataItems = provider.GenerateCompletionData(@"C:\Test.xml", textEditor.ActiveTextAreaControl.TextArea, '<');
using (ICSharpCode.XmlEditor.CodeCompletionWindow completionWindow = ICSharpCode.XmlEditor.CodeCompletionWindow.ShowCompletionWindow(parentForm, textEditor, @"C:\Test.xml", provider, '<')) {
using (CodeCompletionWindow completionWindow = CodeCompletionWindow.ShowCompletionWindow(parentForm, textEditor, @"C:\Test.xml", provider, '<')) {
CodeCompletionListView listView = (CodeCompletionListView)completionWindow.Controls[0];
selectedCompletionData = listView.SelectedCompletionData;
completionWindow.Close();

53
src/AddIns/DisplayBindings/XmlEditor/Test/Completion/ProcessKeyTests.cs

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
namespace XmlEditor.Tests.Completion
{
/// <summary>
/// Tests the XmlCompletionDataProvider's ProcessKey method.
/// </summary>
[TestFixture]
public class ProcessKeyTests
{
XmlCompletionDataProvider provider;
[SetUp]
public void Init()
{
XmlSchemaCompletionDataCollection schemas = new XmlSchemaCompletionDataCollection();
provider = new XmlCompletionDataProvider(schemas, null, null);
}
/// <summary>
/// A space character should be treated as a normal character.
/// </summary>
[Test]
public void SpaceChar()
{
Assert.AreEqual(CompletionDataProviderKeyResult.NormalKey, provider.ProcessKey(' '));
}
[Test]
public void TabChar()
{
Assert.AreEqual(CompletionDataProviderKeyResult.InsertionKey, provider.ProcessKey('\t'));
}
[Test]
public void ReturnChar()
{
Assert.AreEqual(CompletionDataProviderKeyResult.InsertionKey, provider.ProcessKey((char)Keys.Return));
}
}
}

1
src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj

@ -45,6 +45,7 @@ @@ -45,6 +45,7 @@
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Completion\FirstCompletionListItemSelectedTestFixture.cs" />
<Compile Include="Completion\ProcessKeyTests.cs" />
<Compile Include="Parser\XamlMixedNamespaceTestFixture.cs" />
<Compile Include="Paths\QualifiedNameToStringTests.cs" />
<Compile Include="Schema\SingleElementSchemaTestFixture.cs" />

73
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/CompletionWindow/CodeCompletionWindow.cs

@ -16,33 +16,44 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow @@ -16,33 +16,44 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow
public class CodeCompletionWindow : AbstractCompletionWindow
{
ICompletionData[] completionData;
CodeCompletionListView codeCompletionListView;
VScrollBar vScrollBar = new VScrollBar();
CodeCompletionListView codeCompletionListView;
VScrollBar vScrollBar = new VScrollBar();
ICompletionDataProvider dataProvider;
IDocument document;
int startOffset;
int endOffset;
DeclarationViewWindow declarationViewWindow = null;
bool showDeclarationWindow = true;
bool fixedListViewWidth = true;
const int ScrollbarWidth = 16;
const int MaxListLength = 10;
int startOffset;
int endOffset;
DeclarationViewWindow declarationViewWindow = null;
Rectangle workingScreen;
public static CodeCompletionWindow ShowCompletionWindow(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider, char firstChar)
{
return ShowCompletionWindow(parent, control, fileName, completionDataProvider, firstChar, true, true);
}
public static CodeCompletionWindow ShowCompletionWindow(Form parent, TextEditorControl control, string fileName, ICompletionDataProvider completionDataProvider, char firstChar, bool showDeclarationWindow, bool fixedListViewWidth)
{
ICompletionData[] completionData = completionDataProvider.GenerateCompletionData(fileName, control.ActiveTextAreaControl.TextArea, firstChar);
if (completionData == null || completionData.Length == 0) {
return null;
}
CodeCompletionWindow codeCompletionWindow = new CodeCompletionWindow(completionDataProvider, completionData, parent, control);
CodeCompletionWindow codeCompletionWindow = new CodeCompletionWindow(completionDataProvider, completionData, parent, control, showDeclarationWindow, fixedListViewWidth);
codeCompletionWindow.ShowCompletionWindow();
return codeCompletionWindow;
}
CodeCompletionWindow(ICompletionDataProvider completionDataProvider, ICompletionData[] completionData, Form parentForm, TextEditorControl control) : base(parentForm, control)
CodeCompletionWindow(ICompletionDataProvider completionDataProvider, ICompletionData[] completionData, Form parentForm, TextEditorControl control, bool showDeclarationWindow, bool fixedListViewWidth) : base(parentForm, control)
{
this.dataProvider = completionDataProvider;
this.completionData = completionData;
this.document = control.Document;
this.showDeclarationWindow = showDeclarationWindow;
this.fixedListViewWidth = fixedListViewWidth;
workingScreen = Screen.GetWorkingArea(Location);
startOffset = control.ActiveTextAreaControl.Caret.Offset + 1;
endOffset = startOffset;
@ -59,7 +70,6 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow @@ -59,7 +70,6 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow
codeCompletionListView.Click += new EventHandler(CodeCompletionListViewClick);
Controls.Add(codeCompletionListView);
const int MaxListLength = 10;
if (completionData.Length > MaxListLength) {
vScrollBar.Dock = DockStyle.Right;
vScrollBar.Minimum = 0;
@ -70,8 +80,7 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow @@ -70,8 +80,7 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow
Controls.Add(vScrollBar);
}
this.drawingSize = new Size(codeCompletionListView.ItemHeight * 10,
codeCompletionListView.ItemHeight * Math.Min(MaxListLength, completionData.Length));
this.drawingSize = GetListViewSize();
SetLocation();
if (declarationViewWindow == null) {
@ -158,7 +167,7 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow @@ -158,7 +167,7 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow
void CodeCompletionListViewSelectedItemChanged(object sender, EventArgs e)
{
ICompletionData data = codeCompletionListView.SelectedCompletionData;
if (data != null && data.Description != null && data.Description.Length > 0) {
if (showDeclarationWindow && data != null && data.Description != null && data.Description.Length > 0) {
declarationViewWindow.Description = data.Description;
SetDeclarationViewLocation();
} else {
@ -291,5 +300,43 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow @@ -291,5 +300,43 @@ namespace ICSharpCode.TextEditor.Gui.CompletionWindow
Close();
return result;
}
Size GetListViewSize()
{
int height = codeCompletionListView.ItemHeight * Math.Min(MaxListLength, completionData.Length);
int width = codeCompletionListView.ItemHeight * 10;
if (!fixedListViewWidth) {
width = GetListViewWidth(width, height);
}
return new Size(width, height);
}
/// <summary>
/// Gets the list view width large enough to handle the longest completion data
/// text string.
/// </summary>
/// <param name="defaultWidth">The default width of the list view.</param>
/// <param name="height">The height of the list view. This is
/// used to determine if the scrollbar is visible.</param>
/// <returns>The list view width to accommodate the longest completion
/// data text string; otherwise the default width.</returns>
int GetListViewWidth(int defaultWidth, int height)
{
float width = defaultWidth;
using (Graphics graphics = codeCompletionListView.CreateGraphics()) {
for (int i = 0; i < completionData.Length; ++i) {
float itemWidth = graphics.MeasureString(completionData[i].Text.ToString(), codeCompletionListView.Font).Width;
if(itemWidth > width) {
width = itemWidth;
}
}
}
float totalItemsHeight = codeCompletionListView.ItemHeight * completionData.Length;
if (totalItemsHeight > height) {
width += ScrollbarWidth; // Compensate for scroll bar.
}
return (int)width;
}
}
}

Loading…
Cancel
Save