Browse Source

XamlBinding:

- added unit tests
- code clean up
- improved CC for:
  * Trigger
  * EventTrigger
  * MultiTrigger
  * Setter, EventSetter

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4583 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Siegfried Pammer 16 years ago
parent
commit
fb0710f91a
  1. 45
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/DependencyPropertiesTests.cs
  2. 53
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ResolveContextTests.cs
  3. 28
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/TextEditorBasedTests.cs
  4. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XamlBinding.Tests.csproj
  5. 222
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs
  6. 33
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs
  7. 1
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/LookupInfo.cs
  8. 83
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Options/CodeCompletion.xaml
  9. 24
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Options/CodeCompletion.xaml.cs
  10. 6
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Properties/AssemblyInfo.cs
  11. 46
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Utils.cs
  12. 116
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs
  13. 13
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs
  14. 5
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompletionItemList.cs
  15. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlContext.cs
  16. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs
  17. 11
      src/Main/Base/Project/Src/Gui/Dialogs/SharpDevelopColorDialog.cs

45
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/DependencyPropertiesTests.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Dom;
using System;
using NUnit.Framework;
namespace ICSharpCode.XamlBinding.Tests
{
[TestFixture]
public class DependencyPropertiesTests : TextEditorBasedTests
{
//[Test]
public void NormalDependencyPropertiesTest()
{
string fileContent = @"<Window x:Class='XamlTest.Window1'
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
Title='XamlTest' Height='300' Width='300'>
<Grid>
<Button />
</Grid>
</Window>";
int line = 6;
int column = 11;
MockTextEditor textEditor = CreateTextEditor(fileContent, line, column);
XamlCompletionContext context = CompletionDataHelper.ResolveCompletionContext(textEditor, ' ');
var cu = context.ParseInformation.BestCompilationUnit as XamlCompilationUnit;
if (cu == null)
Assert.Fail("cu invalid");
string xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
IReturnType type = cu.CreateType(xmlns, "Grid");
}
}
}

53
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ResolveContextTests.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Linq;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System.IO;
@ -126,5 +127,57 @@ namespace ICSharpCode.XamlBinding.Tests @@ -126,5 +127,57 @@ namespace ICSharpCode.XamlBinding.Tests
Assert.AreEqual(1, context.IgnoredXmlns.Count);
Assert.AreEqual("d", context.IgnoredXmlns[0]);
}
[Test]
public void AncestorDetectionTest1()
{
string xaml = @"<Window x:Class='XamlTest.Window1'
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
Title='XamlTest' Height='300' Width='300'>
<Window.Resources>
<Style TargetType='Button'>
<Setter Property='Background' Value='Blue' />
</Style>
</Window.Resources>
<Grid>
<!-- The width of this button is animated. -->
<Button Name='myWidthAnimatedButton'
Height='30' Width='200' HorizontalAlignment='Left'>
A Button
<Button.Triggers>
<!-- Animates the width of the first button
from 200 to 300. -->
<EventTrigger RoutedEvent='Button.Click'>
<BeginStoryboard>
<Storyboard> <!-- line 20 -->
<DoubleAnimation Storyboard.TargetName='myWidthAnimatedButton'
Storyboard.TargetProperty='Width'
From='200' To='300' Duration='0:0:3' />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Window>";
int line = 22;
int column = 43;
XamlContext context = CompletionDataHelper.ResolveContext(xaml, string.Empty, line, column);
string[] ancestors = new string[] {
"DoubleAnimation", "Storyboard",
"BeginStoryboard", "EventTrigger",
"Button.Triggers", "Button",
"Grid", "Window"
};
Assert.AreEqual("DoubleAnimation", context.ActiveElement.Name);
Assert.AreEqual("Storyboard", context.ParentElement.Name);
Assert.AreEqual(8, context.Ancestors.Count);
Assert.AreEqual(ancestors, context.Ancestors.Select(item => item.Name).ToArray());
}
}
}

28
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/TextEditorBasedTests.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Dom;
using System;
using NUnit.Framework;
namespace ICSharpCode.XamlBinding.Tests
{
public class TextEditorBasedTests
{
protected MockTextEditor CreateTextEditor(string fileContent, int line, int column)
{
MockTextEditor textEditor = new MockTextEditor();
textEditor.Document.Text = fileContent;
textEditor.Caret.Line = line;
textEditor.Caret.Column = column;
textEditor.CreateParseInformation();
return textEditor;
}
}
}

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XamlBinding.Tests.csproj

@ -70,11 +70,13 @@ @@ -70,11 +70,13 @@
<DependentUpon>CompletionTestsBase.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="DependencyPropertiesTests.cs" />
<Compile Include="ExtensionsTests.cs" />
<Compile Include="MockTextEditor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MarkupExtensionTests.cs" />
<Compile Include="ResolveContextTests.cs" />
<Compile Include="TextEditorBasedTests.cs" />
<Compile Include="UtilsTests.cs" />
<Compile Include="XamlExpressionFinderTests.cs" />
<Compile Include="XmlTests.cs" />

222
src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs

@ -59,7 +59,7 @@ namespace ICSharpCode.XamlBinding @@ -59,7 +59,7 @@ namespace ICSharpCode.XamlBinding
{
int offset = Math.Max(0, Math.Min(Utils.GetOffsetFromFilePos(text, line, col), text.Length - 1));
ParseInformation info = ParserService.GetParseInformation(fileName);
ParseInformation info = string.IsNullOrEmpty(fileName) ? null : ParserService.GetParseInformation(fileName);
string attribute = XmlParser.GetAttributeNameAtIndex(text, offset);
bool inAttributeValue = XmlParser.IsInsideAttributeValue(text, offset);
string attributeValue = XmlParser.GetAttributeValueAtIndex(text, offset);
@ -109,17 +109,18 @@ namespace ICSharpCode.XamlBinding @@ -109,17 +109,18 @@ namespace ICSharpCode.XamlBinding
var qAttribute = new QualifiedNameWithLocation(localName, xmlNamespace, prefix, -1, -1);
var context = new XamlContext() {
Description = description,
ActiveElement = lookUpInfo.Active,
ParentElement = lookUpInfo.Parent,
AttributeName = string.IsNullOrEmpty(attribute) ? null : qAttribute,
InRoot = lookUpInfo.IsRoot,
AttributeValue = value,
Description = description,
ActiveElement = lookUpInfo.Active,
ParentElement = lookUpInfo.Parent,
Ancestors = lookUpInfo.Ancestors.ToList(),
AttributeName = string.IsNullOrEmpty(attribute) ? null : qAttribute,
InRoot = lookUpInfo.IsRoot,
AttributeValue = value,
RawAttributeValue = attributeValue,
ValueStartOffset = offsetFromValueStart,
XmlnsDefinitions = lookUpInfo.XmlnsDefinitions,
ParseInformation = info,
IgnoredXmlns = lookUpInfo.IgnoredXmlns.AsReadOnly()
ValueStartOffset = offsetFromValueStart,
XmlnsDefinitions = lookUpInfo.XmlnsDefinitions,
ParseInformation = info,
IgnoredXmlns = lookUpInfo.IgnoredXmlns.AsReadOnly()
};
return context;
@ -182,7 +183,7 @@ namespace ICSharpCode.XamlBinding @@ -182,7 +183,7 @@ namespace ICSharpCode.XamlBinding
return;
foreach (IProperty p in rt.GetProperties()) {
if (p.IsPublic && (p.CanSet || p.ReturnType.IsCollectionReturnType())) {
if (p.IsPublic && (p.IsPubliclySetable() || p.ReturnType.IsCollectionReturnType())) {
list.Add(new XamlCodeCompletionItem(p));
}
}
@ -316,6 +317,8 @@ namespace ICSharpCode.XamlBinding @@ -316,6 +317,8 @@ namespace ICSharpCode.XamlBinding
bool isList = rt != null && rt.IsListReturnType();
bool parentAdded = false;
foreach (var ns in items) {
foreach (var c in ns.Value) {
if (includeAbstract) {
@ -341,10 +344,18 @@ namespace ICSharpCode.XamlBinding @@ -341,10 +344,18 @@ namespace ICSharpCode.XamlBinding
continue;
}
XamlCodeCompletionItem item = new XamlCodeCompletionItem(c, ns.Key);
if (item.Text == last.FullXmlName)
parentAdded = true;
result.Add(new XamlCodeCompletionItem(c, ns.Key));
}
}
if (!parentAdded && !last.FullXmlName.Contains("."))
result.Add(new XamlCodeCompletionItem(cu.CreateType(last.Namespace, last.Name.Trim('.')).GetUnderlyingClass(), last.Prefix));
string xamlPrefix = Utils.GetXamlNamespacePrefix(context);
var xamlItems = XamlNamespaceAttributes.AsEnumerable();
@ -419,7 +430,7 @@ namespace ICSharpCode.XamlBinding @@ -419,7 +430,7 @@ namespace ICSharpCode.XamlBinding
TypeResolveResult trr = new XamlResolver().Resolve(new ExpressionResult(className, context), info, editor.Document.Text) as TypeResolveResult;
IClass typeClass = (trr != null && trr.ResolvedType != null) ? trr.ResolvedType.GetUnderlyingClass() : null;
if (typeClass != null && typeClass.DerivesFrom("System.Windows.DependencyObject"))
if (typeClass != null && typeClass.HasAttached(true, true))
list.Items.AddRange(GetListOfAttached(context, className, ns, true, true));
} else {
QualifiedNameWithLocation last = context.ActiveElement;
@ -575,6 +586,81 @@ namespace ICSharpCode.XamlBinding @@ -575,6 +586,81 @@ namespace ICSharpCode.XamlBinding
break;
}
}
public static string LookForTargetTypeValue(XamlCompletionContext context, out bool isExplicit, params string[] elementName) {
var loc = context.ParentElement.Location;
IList<QualifiedNameWithLocation> ancestors = context.Ancestors;
isExplicit = false;
for (int i = 0; i < ancestors.Count; i++) {
if (ancestors[i].Name == "Style") {
isExplicit = true;
return Utils.GetAttributeValue(
context.Editor.Document.Text,
ancestors[i].Location.Line,
ancestors[i].Location.Column,
"TargetType");
}
if (ancestors[i].Name.EndsWithAny(elementName.Select(s => "." + s + "s"), StringComparison.Ordinal)
&& !ancestors[i].Name.StartsWith("Style.", StringComparison.Ordinal)) {
return ancestors[i].Name.Remove(ancestors[i].Name.IndexOf('.'));
}
}
return null;
}
public static string GetTypeNameFromTypeExtension(MarkupExtensionInfo info, XamlCompletionContext context)
{
IReturnType type = CompletionDataHelper.ResolveType(info.ExtensionType, context)
?? CompletionDataHelper.ResolveType(info.ExtensionType + "Extension", context);
if (type == null || type.FullyQualifiedName != "System.Windows.Markup.TypeExtension")
return string.Empty;
var item = info.PositionalArguments.FirstOrDefault();
if (item != null && item.IsString) {
return item.StringValue;
} else {
if (info.NamedArguments.TryGetValue("typename", out item)) {
if (item.IsString)
return item.StringValue;
}
}
return string.Empty;
}
public static bool EndsWithAny(this string thisValue, IEnumerable<string> items, StringComparison comparison)
{
foreach (string item in items) {
if (thisValue.EndsWith(item, comparison))
return true;
}
return false;
}
static IReturnType GetType(XamlCompletionContext context, out bool isExplicit)
{
AttributeValue value = MarkupExtensionParser.ParseValue(LookForTargetTypeValue(context, out isExplicit, "Trigger", "Setter") ?? string.Empty);
IReturnType typeName = null;
string typeNameString = null;
if (!value.IsString) {
typeNameString = GetTypeNameFromTypeExtension(value.ExtensionValue, context);
typeName = CompletionDataHelper.ResolveType(typeNameString, context);
} else {
typeNameString = value.StringValue;
typeName = CompletionDataHelper.ResolveType(value.StringValue, context);
}
return typeName;
}
public static IEnumerable<ICompletionItem> MemberCompletion(XamlCompletionContext context, IReturnType type, string textPrefix)
{
@ -595,6 +681,9 @@ namespace ICSharpCode.XamlBinding @@ -595,6 +681,9 @@ namespace ICSharpCode.XamlBinding
yield break;
}
bool isExplicit;
IReturnType typeName;
switch (c.ClassType) {
case ClassType.Class:
switch (c.FullyQualifiedName) {
@ -605,6 +694,26 @@ namespace ICSharpCode.XamlBinding @@ -605,6 +694,26 @@ namespace ICSharpCode.XamlBinding
foreach (var item in CreateElementList(context, true, true))
yield return item;
break;
case "System.Windows.PropertyPath":
break;
case "System.Windows.DependencyProperty":
typeName = GetType(context, out isExplicit);
bool isReadOnly = context.ActiveElement.Name.EndsWith("Trigger");
if (typeName != null) {
foreach (var item in typeName.GetDependencyProperties(true, !isExplicit, !isReadOnly))
yield return item;
}
break;
case "System.Windows.RoutedEvent":
typeName = GetType(context, out isExplicit);
if (typeName != null) {
foreach (var item in typeName.GetRoutedEvents(true, !isExplicit))
yield return item;
}
break;
default:
if (context.Description == XamlContextDescription.InMarkupExtension) {
foreach (IField f in c.Fields)
@ -803,13 +912,8 @@ namespace ICSharpCode.XamlBinding @@ -803,13 +912,8 @@ namespace ICSharpCode.XamlBinding
static bool CompareParameter(IParameter p1, IParameter p2)
{
bool result = p1.ReturnType.DotNetName == p2.ReturnType.DotNetName;
result &= (p1.IsOut == p2.IsOut);
result &= (p1.IsParams == p2.IsParams);
result &= (p1.IsRef == p2.IsRef);
return result;
return (p1.ReturnType.DotNetName == p2.ReturnType.DotNetName) &&
(p1.IsOut == p2.IsOut) && (p1.IsParams == p2.IsParams) && (p1.IsRef == p2.IsRef);
}
static IDictionary<string, IEnumerable<IClass>> GetClassesFromContext(XamlCompletionContext context)
@ -827,8 +931,60 @@ namespace ICSharpCode.XamlBinding @@ -827,8 +931,60 @@ namespace ICSharpCode.XamlBinding
return result;
}
public static bool IsPubliclySetable(this IProperty thisValue)
{
return thisValue.CanSet &&
(thisValue.SetterModifiers == ModifierEnum.None ||
(thisValue.SetterModifiers & ModifierEnum.Public) == ModifierEnum.Public);
}
public static IEnumerable<ICompletionItem> GetDependencyProperties(this IReturnType type, bool excludeSuffix, bool addType, bool requiresSetable)
{
foreach (var field in type.GetFields()) {
if (field.ReturnType.FullyQualifiedName != "System.Windows.DependencyProperty")
continue;
if (field.Name.Length <= "Property".Length || !field.Name.EndsWith("Property", StringComparison.Ordinal))
continue;
string fieldName = field.Name.Remove(field.Name.Length - "Property".Length);
IProperty property = type.GetProperties().FirstOrDefault(p => p.Name == fieldName);
if (property == null)
continue;
if (requiresSetable && property.IsPubliclySetable())
if (!excludeSuffix)
fieldName += "Property";
if (addType)
fieldName = type.Name + "." + fieldName;
yield return new XamlCodeCompletionItem(fieldName, field);
}
}
public static IEnumerable<ICompletionItem> GetRoutedEvents(this IReturnType type, bool excludeSuffix, bool addType)
{
foreach (var field in type.GetFields()) {
if (field.ReturnType.FullyQualifiedName != "System.Windows.RoutedEvent")
continue;
if (field.Name.Length <= "Event".Length || !field.Name.EndsWith("Event", StringComparison.Ordinal))
continue;
string fieldName = field.Name.Remove(field.Name.Length - "Event".Length);
if (!type.GetEvents().Any(p => p.Name == fieldName))
continue;
if (!excludeSuffix)
fieldName += "Event";
if (addType)
fieldName = type.Name + "." + fieldName;
yield return new XamlCodeCompletionItem(fieldName, field);
}
}
static List<ICompletionItem> GetListOfAttached(XamlCompletionContext context, string prefixClassName, string prefixNamespace, bool events, bool properties)
internal static List<ICompletionItem> GetListOfAttached(XamlCompletionContext context, string prefixClassName, string prefixNamespace, bool events, bool properties)
{
List<ICompletionItem> result = new List<ICompletionItem>();
@ -840,10 +996,8 @@ namespace ICSharpCode.XamlBinding @@ -840,10 +996,8 @@ namespace ICSharpCode.XamlBinding
if (!string.IsNullOrEmpty(prefixClassName)) {
var ns = context.XmlnsDefinitions[prefixNamespace];
IClass c = XamlCompilationUnit.GetNamespaceMembers(pc, ns).FirstOrDefault(item => item.Name == prefixClassName);
if (c != null) {
if (!(c.IsAbstract
&& !c.ClassInheritanceTree.Any(b => b.FullyQualifiedName == "System.Attribute")
&& c.Methods.Any(m => m.IsConstructor && m.IsPublic))) {
if (c != null && c.ClassType == ClassType.Class) {
if (!c.ClassInheritanceTree.Any(b => b.FullyQualifiedName == "System.Attribute")) {
prefixNamespace = string.IsNullOrEmpty(prefixNamespace) ? prefixNamespace : prefixNamespace + ":";
if (properties)
AddAttachedProperties(c, result, prefixNamespace, prefixNamespace + prefixClassName);
@ -858,12 +1012,6 @@ namespace ICSharpCode.XamlBinding @@ -858,12 +1012,6 @@ namespace ICSharpCode.XamlBinding
foreach (IClass c in XamlCompilationUnit.GetNamespaceMembers(pc, ns.Value)) {
if (c.ClassType != ClassType.Class)
continue;
if (c.IsAbstract && c.IsStatic)
continue;
if (c.ClassInheritanceTree.Any(b => b.FullyQualifiedName == "System.Attribute"))
continue;
if (!c.Methods.Any(m => m.IsConstructor && m.IsPublic))
continue;
if (c.HasAttached(properties, events))
result.Add(new XamlCodeCompletionItem(c, ns.Key));
}
@ -873,7 +1021,7 @@ namespace ICSharpCode.XamlBinding @@ -873,7 +1021,7 @@ namespace ICSharpCode.XamlBinding
return result;
}
static void AddAttachedProperties(IClass c, List<ICompletionItem> result, string key, string prefix)
public static void AddAttachedProperties(IClass c, List<ICompletionItem> result, string key, string prefix)
{
var attachedProperties = c.Fields
.Where(f =>
@ -917,15 +1065,7 @@ namespace ICSharpCode.XamlBinding @@ -917,15 +1065,7 @@ namespace ICSharpCode.XamlBinding
f.ReturnType != null &&
f.ReturnType.FullyQualifiedName == "System.Windows.RoutedEvent" &&
f.Name.Length > "Event".Length &&
f.Name.EndsWith("Event", StringComparison.Ordinal) &&
c.Methods.Any(m =>
m.IsPublic &&
m.IsStatic &&
m.Name.Length > 3 &&
(m.Name.StartsWith("Add", StringComparison.Ordinal) || m.Name.StartsWith("Remove", StringComparison.Ordinal)) &&
m.Name.EndsWith("Handler", StringComparison.Ordinal) &&
IsMethodFromEvent(f, m)
)
f.Name.EndsWith("Event", StringComparison.Ordinal)
);
int prefixLength = (prefix.Length > 0) ? prefix.Length + 1 : 0;

33
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs

@ -265,9 +265,7 @@ namespace ICSharpCode.XamlBinding @@ -265,9 +265,7 @@ namespace ICSharpCode.XamlBinding
bool foundMethod = false;
if (lookForProperties) {
if (field.ReturnType.FullyQualifiedName != "System.Windows.DependencyProperty")
continue;
if (lookForProperties && field.ReturnType.FullyQualifiedName == "System.Windows.DependencyProperty") {
if (field.Name.Length <= "Property".Length)
continue;
if (!field.Name.EndsWith("Property", StringComparison.Ordinal))
@ -286,38 +284,13 @@ namespace ICSharpCode.XamlBinding @@ -286,38 +284,13 @@ namespace ICSharpCode.XamlBinding
}
}
if (lookForEvents && !foundMethod) {
if (field.ReturnType.FullyQualifiedName != "System.Windows.RoutedEvent")
continue;
if (lookForEvents && !foundMethod && field.ReturnType.FullyQualifiedName == "System.Windows.RoutedEvent") {
if (field.Name.Length <= "Event".Length)
continue;
if (!field.Name.EndsWith("Event", StringComparison.Ordinal))
continue;
string fieldName = field.Name.Remove(field.Name.Length - "Event".Length);
foreach (IMethod method in thisValue.Methods) {
if (!method.IsPublic || !method.IsStatic || method.Name.Length <= 3)
continue;
string methodName = string.Empty;
if (methodName.EndsWith("Handler", StringComparison.Ordinal))
methodName = method.Name.Remove(method.Name.Length - "Handler".Length);
else
continue;
if (methodName.StartsWith("Add"))
methodName = methodName.Remove(0, 3);
else if (methodName.StartsWith("Remove"))
methodName = methodName.Remove(0, 6);
else
continue;
foundMethod = methodName == fieldName;
if (foundMethod)
return true;
}
return true;
}
}

1
src/AddIns/BackendBindings/XamlBinding/XamlBinding/LookupInfo.cs

@ -25,6 +25,7 @@ namespace ICSharpCode.XamlBinding @@ -25,6 +25,7 @@ namespace ICSharpCode.XamlBinding
public Dictionary<string, string> XmlnsDefinitions { get; set; }
public List<string> IgnoredXmlns { get; set; }
public QualifiedNameWithLocation Active { get; set; }
public Stack<QualifiedNameWithLocation> Ancestors { get; set; }
public QualifiedNameWithLocation Parent { get; set; }
public int ActiveElementStartIndex { get; set; }
public bool IsRoot { get; set; }

83
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Options/CodeCompletion.xaml

@ -1,47 +1,38 @@ @@ -1,47 +1,38 @@
<gui:OptionPanel x:Class="ICSharpCode.XamlBinding.Options.CodeCompletion"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:gui="clr-namespace:ICSharpCode.SharpDevelop.Gui;assembly=ICSharpCode.SharpDevelop"
xmlns:addin="clr-namespace:ICSharpCode.XamlBinding"
xmlns:sd="http://icsharpcode.net/sharpdevelop/core"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<gui:OptionPanel.Resources>
<Style x:Key="ColorComboBox" TargetType="ComboBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding}" Width="14" Height="14" Margin="2" SnapsToDevicePixels="True" Stroke="Black" />
<TextBlock Text="{Binding}" Margin="5,0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsSource" Value="{x:Static addin:XamlBindingOptions.Colors}" />
</Style>
</gui:OptionPanel.Resources>
<StackPanel>
<GroupBox Header="{sd:Localize AddIns.XamlBinding.Options.CodeCompletionGroupLabel}">
<StackPanel>
<CheckBox Content="{sd:Localize AddIns.XamlBinding.Options.UseExtensionCompletion}"
IsChecked="{sd:OptionBinding addin:XamlBindingOptions.UseExtensionCompletion}" />
<CheckBox Content="{sd:Localize AddIns.XamlBinding.Options.SwitchToCodeViewAfterInsertion}"
IsChecked="{sd:OptionBinding addin:XamlBindingOptions.SwitchToCodeViewAfterInsertion}" />
<DockPanel>
<Label Content="{sd:Localize AddIns.XamlBinding.Options.EventHandlerNamePattern}" />
<TextBox Text="{sd:OptionBinding addin:XamlBindingOptions.EventHandlerNamePattern}" />
</DockPanel>
</StackPanel>
</GroupBox>
<GroupBox Header="{sd:Localize AddIns.XamlBinding.Options.HighlightingGroupLabel}">
<StackPanel>
<TextBlock Margin="3" Text="{sd:Localize AddIns.XamlBinding.Options.HighlightingDescription}" />
<DockPanel>
<Label Content="{sd:Localize AddIns.XamlBinding.Options.PropertyColor}" />
<ComboBox x:Name="cmbPropertyColor"
SelectedValue="{sd:OptionBinding addin:XamlBindingOptions.PropertyForegroundBrush}"
Style="{StaticResource ColorComboBox}" />
</DockPanel>
</StackPanel>
</GroupBox>
</StackPanel>
<gui:OptionPanel x:Class="ICSharpCode.XamlBinding.Options.CodeCompletion" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:gui="clr-namespace:ICSharpCode.SharpDevelop.Gui;assembly=ICSharpCode.SharpDevelop" xmlns:addin="clr-namespace:ICSharpCode.XamlBinding" xmlns:sd="http://icsharpcode.net/sharpdevelop/core" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<GroupBox Header="{sd:Localize AddIns.XamlBinding.Options.CodeCompletionGroupLabel}">
<StackPanel>
<CheckBox Content="{sd:Localize AddIns.XamlBinding.Options.UseExtensionCompletion}" IsChecked="{sd:OptionBinding addin:XamlBindingOptions.UseExtensionCompletion}" />
<CheckBox Content="{sd:Localize AddIns.XamlBinding.Options.SwitchToCodeViewAfterInsertion}" IsChecked="{sd:OptionBinding addin:XamlBindingOptions.SwitchToCodeViewAfterInsertion}" />
<DockPanel>
<Label Content="{sd:Localize AddIns.XamlBinding.Options.EventHandlerNamePattern}" />
<TextBox Text="{sd:OptionBinding addin:XamlBindingOptions.EventHandlerNamePattern}" />
</DockPanel>
</StackPanel>
</GroupBox>
<GroupBox Header="{sd:Localize AddIns.XamlBinding.Options.HighlightingGroupLabel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="1" DockPanel.Dock="Left" Content="{sd:Localize AddIns.XamlBinding.Options.PropertyColor}" Grid.Column="0" />
<Label Grid.Row="2" DockPanel.Dock="Left" Content="{sd:Localize AddIns.XamlBinding.Options.EventColor}" Grid.Column="0" />
<Label Grid.Row="3" DockPanel.Dock="Left" Content="{sd:Localize AddIns.XamlBinding.Options.NamespaceDeclarationColor}" Grid.Column="0" />
<Label Grid.Row="4" DockPanel.Dock="Left" Content="{sd:Localize AddIns.XamlBinding.Options.IngoredElementColor}" Grid.Column="0" />
<Button Grid.Row="1" Background="{sd:OptionBinding addin:XamlBindingOptions.PropertyForegroundBrush}" Content="{sd:OptionBinding addin:XamlBindingOptions.PropertyForegroundBrush}" Foreground="WhiteSmoke" Click="ButtonClick" Grid.Column="1" />
<TextBlock Grid.ColumnSpan="1" Margin="3" Text="{sd:Localize AddIns.XamlBinding.Options.HighlightingDescription}" Grid.Column="0" Grid.Row="0" />
<Button Grid.Row="2" Background="{sd:OptionBinding addin:XamlBindingOptions.EventForegroundBrush}" Content="{sd:OptionBinding addin:XamlBindingOptions.EventForegroundBrush}" Foreground="WhiteSmoke" Click="ButtonClick" Grid.Column="1" />
<Button Grid.Row="3" Background="{sd:OptionBinding addin:XamlBindingOptions.NamespaceDeclarationForegroundBrush}" Content="{sd:OptionBinding addin:XamlBindingOptions.NamespaceDeclarationForegroundBrush}" Foreground="WhiteSmoke" Click="ButtonClick" Grid.Column="1" />
<Button Grid.Row="4" Background="{sd:OptionBinding addin:XamlBindingOptions.IgnoredForegroundBrush}" Content="{sd:OptionBinding addin:XamlBindingOptions.IgnoredForegroundBrush}" Foreground="WhiteSmoke" Click="ButtonClick" Grid.Column="1" />
</Grid>
</GroupBox>
</StackPanel>
</gui:OptionPanel>

24
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Options/CodeCompletion.xaml.cs

@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using ICSharpCode.SharpDevelop.Gui;
using System;
using System.Collections.Generic;
using System.Text;
@ -17,6 +16,8 @@ using System.Windows.Documents; @@ -17,6 +16,8 @@ using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.XamlBinding.Options
{
/// <summary>
@ -28,5 +29,26 @@ namespace ICSharpCode.XamlBinding.Options @@ -28,5 +29,26 @@ namespace ICSharpCode.XamlBinding.Options
{
InitializeComponent();
}
void ButtonClick(object sender, RoutedEventArgs e)
{
SharpDevelopColorDialog dialog = new SharpDevelopColorDialog();
if (dialog.ShowWpfDialog() ?? false) {
Button b = sender as Button;
b.Background = new SolidColorBrush(dialog.WpfColor);
b.Content = (sender as Button).Background;
}
}
public override bool SaveOptions()
{
if (base.SaveOptions()) {
XamlColorizer.RefreshAll();
return true;
}
return false;
}
}
}

6
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Properties/AssemblyInfo.cs

@ -1,10 +1,12 @@ @@ -1,10 +1,12 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com"/>
// <version>$Revision: 2564 $</version>
// </file>
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyDescription("Provides XAML integration in code-completion")]
[assembly: AssemblyDescription("Provides XAML integration in code-completion")]
[assembly: InternalsVisibleTo("XamlBinding.Tests")]

46
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Utils.cs

@ -61,21 +61,8 @@ namespace ICSharpCode.XamlBinding @@ -61,21 +61,8 @@ namespace ICSharpCode.XamlBinding
try {
XmlReader reader = CreateReaderAtTarget(text, line, col);
if (!reader.MoveToFirstAttribute()) {
/* int offset = GetOffsetFromFilePos(text, line, col) + 1;
if (XmlParser.IsInsideAttributeValue(text, offset))
text = text.Substring(0, offset) + "\">";
else {
if (!string.IsNullOrEmpty(XmlParser.GetAttributeNameAtIndex(text, offset)))
text = text.Substring(0, offset) + "=\"\">";
else
text = text.Substring(0, offset) + ">";
}
reader = CreateReaderAtTarget(text, line, col);
if (!reader.MoveToFirstAttribute()) */
if (!reader.MoveToFirstAttribute())
return null;
}
do {
LoggingService.Debug("name: " + reader.Name + " value: " + reader.Value);
string plainName = reader.Name.ToUpperInvariant();
@ -188,30 +175,6 @@ namespace ICSharpCode.XamlBinding @@ -188,30 +175,6 @@ namespace ICSharpCode.XamlBinding
return offset + col - 1;
}
public static int GetParentElementStart(ITextEditor editor)
{
Stack<int> offsetStack = new Stack<int>();
using (XmlTextReader xmlReader = new XmlTextReader(new StringReader(editor.Document.GetText(0, editor.Caret.Offset)))) {
try {
xmlReader.XmlResolver = null; // prevent XmlTextReader from loading external DTDs
while (xmlReader.Read()) {
switch (xmlReader.NodeType) {
case XmlNodeType.Element:
if (!xmlReader.IsEmptyElement) {
offsetStack.Push(editor.Document.PositionToOffset(xmlReader.LineNumber, xmlReader.LinePosition));
}
break;
case XmlNodeType.EndElement:
offsetStack.Pop();
break;
}
}
} catch (XmlException) { }
}
return (offsetStack.Count > 0) ? offsetStack.Pop() : -1;
}
static QualifiedNameWithLocation ResolveCurrentElement(string text, int offset, Dictionary<string, string> xmlnsDefinitions)
{
if (offset < 0)
@ -319,12 +282,19 @@ namespace ICSharpCode.XamlBinding @@ -319,12 +282,19 @@ namespace ICSharpCode.XamlBinding
if (active == null)
active = parent;
if (parent != null)
stack.Push(parent);
if (active != null && active != parent)
stack.Push(active);
return new LookupInfo() {
Active = active,
ActiveElementStartIndex = activeElementStartIndex,
IgnoredXmlns = ignoredXmlns,
IsRoot = isRoot,
Parent = parent,
Ancestors = stack,
XmlnsDefinitions = xmlns
};
}

116
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs

@ -176,20 +176,20 @@ namespace ICSharpCode.XamlBinding @@ -176,20 +176,20 @@ namespace ICSharpCode.XamlBinding
if (!DoMarkupExtensionCompletion(context)) {
var completionList = new XamlCompletionItemList();
var mrr = XamlResolver.Resolve(context.AttributeName.FullXmlName, context) as MemberResolveResult;
if (mrr != null && mrr.ResolvedType != null) {
completionList.Items.AddRange(CompletionDataHelper.MemberCompletion(context, mrr.ResolvedType, string.Empty));
editor.ShowInsightWindow(CompletionDataHelper.MemberInsight(mrr));
}
if (context.ActiveElement.Name == "Setter" || context.ActiveElement.Name == "EventSetter")
if ((context.ActiveElement.Name == "Setter" || context.ActiveElement.Name == "EventSetter") && context.AttributeName.Name == "Value")
DoSetterAndEventSetterCompletion(context, completionList);
else if ((context.ActiveElement.Name.EndsWith("Trigger") || context.ActiveElement.Name == "Condition") && context.AttributeName.Name == "Value")
DoTriggerCompletion(context, completionList);
else {
var mrr = XamlResolver.Resolve(context.AttributeName.FullXmlName, context) as MemberResolveResult;
if (mrr != null && mrr.ResolvedType != null) {
completionList.Items.AddRange(CompletionDataHelper.MemberCompletion(context, mrr.ResolvedType, string.Empty));
editor.ShowInsightWindow(CompletionDataHelper.MemberInsight(mrr));
}
}
completionList.PreselectionLength = editor.GetWordBeforeCaretExtended().Length;
if (context.AttributeName.Name == "TypeArguments" && context.AttributeName.Namespace == CompletionDataHelper.XamlNamespace)
DoTypeArgumentsCompletion(context, completionList);
completionList.SortItems();
if (context.AttributeName.Prefix.Equals("xmlns", StringComparison.OrdinalIgnoreCase) ||
@ -209,28 +209,61 @@ namespace ICSharpCode.XamlBinding @@ -209,28 +209,61 @@ namespace ICSharpCode.XamlBinding
return false;
}
static void DoTypeArgumentsCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) {
completionList.Items.AddRange(CompletionDataHelper.CreateElementList(context, false, true));
if (context.ValueStartOffset < 1)
return;
string starter = context.Editor.GetWordBeforeCaretExtended();
int lastComma = starter.LastIndexOf(',');
if (lastComma > -1)
starter = starter.Substring(lastComma).TrimStart(',', ' ', '\t');
completionList.PreselectionLength = starter.Length;
static void DoTriggerCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) {
bool isExplicit;
AttributeValue value = MarkupExtensionParser.ParseValue(CompletionDataHelper.LookForTargetTypeValue(context, out isExplicit, "Trigger") ?? string.Empty);
IReturnType typeName = null;
string typeNameString = null;
if (!value.IsString) {
typeNameString = CompletionDataHelper.GetTypeNameFromTypeExtension(value.ExtensionValue, context);
typeName = CompletionDataHelper.ResolveType(typeNameString, context);
} else {
typeNameString = value.StringValue;
typeName = CompletionDataHelper.ResolveType(value.StringValue, context);
}
if (typeName != null) {
switch (context.AttributeName.Name) {
case "Value":
var loc2 = context.ActiveElement.Location;
AttributeValue propType = MarkupExtensionParser.ParseValue(
Utils.GetAttributeValue(context.Editor.Document.Text, loc2.Line,
loc2.Column, "Property"));
if (!propType.IsString)
break;
string name = propType.StringValue;
if (!name.Contains("."))
name = typeNameString + "." + name;
context.Description = XamlContextDescription.AtTag;
var member = XamlResolver.Resolve(name, context) as MemberResolveResult;
if (member == null || member.ResolvedMember == null)
break;
completionList.Items.AddRange(
CompletionDataHelper.MemberCompletion(context, member.ResolvedMember.ReturnType, string.Empty)
);
break;
}
}
}
static void DoSetterAndEventSetterCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) {
int offset = Utils.GetParentElementStart(context.Editor);
var loc = context.Editor.Document.OffsetToPosition(offset);
AttributeValue value = MarkupExtensionParser.ParseValue(Utils.GetAttributeValue(context.Editor.Document.Text, loc.Line, loc.Column, "TargetType") ?? string.Empty);
bool isExplicit;
string element = context.ParentElement.Name.EndsWith("Trigger") ? "Trigger" : context.ParentElement.Name;
AttributeValue value = MarkupExtensionParser.ParseValue(CompletionDataHelper.LookForTargetTypeValue(context, out isExplicit, element) ?? string.Empty);
IReturnType typeName = null;
string typeNameString = null;
if (!value.IsString) {
typeNameString = GetTypeNameFromTypeExtension(value.ExtensionValue, context);
typeNameString = CompletionDataHelper.GetTypeNameFromTypeExtension(value.ExtensionValue, context);
typeName = CompletionDataHelper.ResolveType(typeNameString, context);
} else {
typeNameString = value.StringValue;
@ -249,7 +282,12 @@ namespace ICSharpCode.XamlBinding @@ -249,7 +282,12 @@ namespace ICSharpCode.XamlBinding
context.Description = XamlContextDescription.AtTag;
var member = XamlResolver.Resolve(typeNameString + "." + propType.StringValue, context) as MemberResolveResult;
string name = propType.StringValue;
if (!name.Contains("."))
name = typeNameString + "." + name;
var member = XamlResolver.Resolve(name, context) as MemberResolveResult;
if (member == null || member.ResolvedMember == null)
break;
@ -282,7 +320,12 @@ namespace ICSharpCode.XamlBinding @@ -282,7 +320,12 @@ namespace ICSharpCode.XamlBinding
if (!evtType.IsString)
break;
var evtMember = XamlResolver.Resolve(typeNameString + "." + evtType.StringValue, context) as MemberResolveResult;
string evtName = evtType.StringValue;
if (!evtName.Contains("."))
evtName = typeNameString + "." + evtName;
var evtMember = XamlResolver.Resolve(evtName, context) as MemberResolveResult;
if (evtMember == null || evtMember.ResolvedMember == null || !(evtMember.ResolvedMember is IEvent) || evtMember.ResolvedMember.ReturnType == null)
break;
@ -308,27 +351,6 @@ namespace ICSharpCode.XamlBinding @@ -308,27 +351,6 @@ namespace ICSharpCode.XamlBinding
}
}
}
static string GetTypeNameFromTypeExtension(MarkupExtensionInfo info, XamlCompletionContext context)
{
IReturnType type = CompletionDataHelper.ResolveType(info.ExtensionType, context)
?? CompletionDataHelper.ResolveType(info.ExtensionType + "Extension", context);
if (type == null || type.FullyQualifiedName != "System.Windows.Markup.TypeExtension")
return string.Empty;
var item = info.PositionalArguments.FirstOrDefault();
if (item != null && item.IsString) {
return item.StringValue;
} else {
if (info.NamedArguments.TryGetValue("typename", out item)) {
if (item.IsString)
return item.StringValue;
}
}
return string.Empty;
}
static bool DoMarkupExtensionCompletion(XamlCompletionContext context)
{

13
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs

@ -182,6 +182,18 @@ namespace ICSharpCode.XamlBinding @@ -182,6 +182,18 @@ namespace ICSharpCode.XamlBinding
WeakLineTracker.Register(this.Editor.Document.GetService(typeof(TextDocument)) as TextDocument, this);
ParserService.LoadSolutionProjectsThreadEnded += ParserServiceLoadSolutionProjectsThreadEnded;
colorizers.Add(this);
}
static IList<XamlColorizer> colorizers = new List<XamlColorizer>();
public static void RefreshAll()
{
foreach (XamlColorizer colorizer in colorizers) {
colorizer.RebuildDocument();
colorizer.TextView.Redraw();
}
}
void ParserServiceLoadSolutionProjectsThreadEnded(object sender, EventArgs e)
@ -200,6 +212,7 @@ namespace ICSharpCode.XamlBinding @@ -200,6 +212,7 @@ namespace ICSharpCode.XamlBinding
{
if (!disposed) {
ParserService.LoadSolutionProjectsThreadEnded -= ParserServiceLoadSolutionProjectsThreadEnded;
colorizers.Remove(this);
}
disposed = true;
}

5
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompletionItemList.cs

@ -118,6 +118,11 @@ namespace ICSharpCode.XamlBinding @@ -118,6 +118,11 @@ namespace ICSharpCode.XamlBinding
context.Editor.Caret.Offset -= 4;
break;
}
if (item.Text.StartsWith("/", StringComparison.OrdinalIgnoreCase)) {
context.Editor.Document.Insert(context.EndOffset, ">");
context.Editor.Caret.Offset++;
}
}
}

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlContext.cs

@ -23,6 +23,7 @@ namespace ICSharpCode.XamlBinding @@ -23,6 +23,7 @@ namespace ICSharpCode.XamlBinding
public class XamlContext : ExpressionContext {
public QualifiedNameWithLocation ActiveElement { get; set; }
public QualifiedNameWithLocation ParentElement { get; set; }
public List<QualifiedNameWithLocation> Ancestors { get; set; }
public QualifiedNameWithLocation AttributeName { get; set; }
public AttributeValue AttributeValue { get; set; }
public string RawAttributeValue { get; set; }
@ -47,6 +48,7 @@ namespace ICSharpCode.XamlBinding @@ -47,6 +48,7 @@ namespace ICSharpCode.XamlBinding
public XamlCompletionContext(XamlContext context)
{
this.ActiveElement = context.ActiveElement;
this.Ancestors = context.Ancestors;
this.AttributeName = context.AttributeName;
this.AttributeValue = context.AttributeValue;
this.Description = context.Description;

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs

@ -224,6 +224,8 @@ namespace ICSharpCode.XamlBinding @@ -224,6 +224,8 @@ namespace ICSharpCode.XamlBinding
return null;
if (propertyOrEvent is IEvent && callingClass != null) {
return new MethodGroupResolveResult(callingClass, null, callingClass.DefaultReturnType, expression);
} else if (propertyOrEvent is IProperty && callingClass != null) {
return ResolveElementName(expression);
}
if (propertyOrEvent.Name == "Name" && callingClass != null) {

11
src/Main/Base/Project/Src/Gui/Dialogs/SharpDevelopColorDialog.cs

@ -82,5 +82,16 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -82,5 +82,16 @@ namespace ICSharpCode.SharpDevelop.Gui
{
PropertyService.Set(CustomColorsPropertyName, CustomColorsToString(CustomColors));
}
public bool? ShowWpfDialog()
{
return ShowDialog() == DialogResult.OK;
}
public System.Windows.Media.Color WpfColor {
get {
return System.Windows.Media.Color.FromArgb(this.Color.A, this.Color.R, this.Color.G, this.Color.B);
}
}
}
}

Loading…
Cancel
Save