Browse Source

Merge branch 'newNR' of github.com:icsharpcode/SharpDevelop into newNRILSpyDebugger

newNRILSpyDebugger
Siegfried Pammer 12 years ago
parent
commit
bbf50c05e6
  1. 14
      data/resources/image/BitmapResources/BitmapList.txt
  2. 3
      data/resources/image/BitmapResources/BitmapResources.res
  3. BIN
      data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.AssemblyError.png
  4. BIN
      data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.AssemblyFromFile.png
  5. BIN
      data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.AssemblyFromGAC.png
  6. BIN
      data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.Module.png
  7. BIN
      data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.ModuleError.png
  8. BIN
      data/resources/image/BitmapResources/DebuggerIcons/Icons.16x16.Debug.Assembly.png
  9. 7
      src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs
  10. 4
      src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj
  11. 16
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CaretNavigationTests.cs
  12. 97
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs
  13. 200
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
  14. 48
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  15. 16
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs
  16. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs
  17. 13
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
  18. 27
      src/Main/Base/Project/Dom/ClassBrowser/AssemblyLoadErrorTreeNode.cs
  19. 26
      src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs
  20. 4
      src/Main/Base/Project/Dom/ClassBrowser/TypeDefinitionTreeNode.cs
  21. 25
      src/Main/Base/Project/Dom/ClassBrowser/WorkspaceTreeNode.cs
  22. 11
      src/Main/Base/Project/Dom/IAssemblyModel.cs
  23. 31
      src/Main/Base/Project/Dom/IEntityModelContext.cs
  24. 21
      src/Main/Base/Project/ICSharpCode.SharpDevelop.addin
  25. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  26. 1
      src/Main/Base/Project/Src/Editor/Dialogs/RenameSymbolDialog.xaml.cs
  27. 46
      src/Main/Base/Project/Src/Gui/Pads/DefinitionViewPad.cs
  28. 6
      src/Main/SharpDevelop/Dom/AssemblyModel.cs
  29. 229
      src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs
  30. 4
      src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserTreeNodesFactory.cs
  31. 75
      src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs
  32. 29
      src/Main/SharpDevelop/Dom/ClassBrowser/OpenAssemblyCommand.cs
  33. 46
      src/Main/SharpDevelop/Dom/ClassBrowser/OpenFromGacDialog.xaml
  34. 188
      src/Main/SharpDevelop/Dom/ClassBrowser/OpenFromGacDialog.xaml.cs
  35. BIN
      src/Main/SharpDevelop/Resources/BitmapResources.resources
  36. 7
      src/Main/SharpDevelop/SharpDevelop.csproj

14
data/resources/image/BitmapResources/BitmapList.txt

@ -140,7 +140,9 @@ SharpQueryIcons\Icons.16x16.SharpQuery.Column.png
SharpQueryIcons\Icons.16x16.SharpQuery.NodeError.png SharpQueryIcons\Icons.16x16.SharpQuery.NodeError.png
SharpQueryIcons\Icons.16x16.SharpQuery.Remove.png SharpQueryIcons\Icons.16x16.SharpQuery.Remove.png
SharpQueryIcons\Icons.16x16.SharpQuery.Table.png SharpQueryIcons\Icons.16x16.SharpQuery.Table.png
ClassBrowserIcons\Icons.16x16.Workspace.png
ClassBrowserIcons\Icons.16x16.Assembly.png
ClassBrowserIcons\Icons.16x16.AssemblyError.png
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copied from the Fugue Icon Library and modified or mashed up with other Fugue Copied from the Fugue Icon Library and modified or mashed up with other Fugue
@ -239,6 +241,11 @@ CodeCoverageIcons\CodeCoverage.Icons.16x16.Pad.png
CodeCoverageIcons\CodeCoverage.Icons.16x16.Run.png CodeCoverageIcons\CodeCoverage.Icons.16x16.Run.png
DebuggerIcons\Icons.16x16.Debug.Start.png DebuggerIcons\Icons.16x16.Debug.Start.png
DebuggerIcons\Icons.16x16.Debug.StartWithoutDebugging.png DebuggerIcons\Icons.16x16.Debug.StartWithoutDebugging.png
DebuggerIcons\Icons.16x16.Debug.Assembly.png
ClassBrowserIcons\Icons.16x16.Module.png
ClassBrowserIcons\Icons.16x16.ModuleError.png
ClassBrowserIcons\Icons.16x16.AssemblyFromFile.png
ClassBrowserIcons\Icons.16x16.AssemblyFromGAC.png
NavigationIcons\Icons.16x16.NavigateBack.disabled.png NavigationIcons\Icons.16x16.NavigateBack.disabled.png
NavigationIcons\Icons.16x16.NavigateBack.png NavigationIcons\Icons.16x16.NavigateBack.png
NavigationIcons\Icons.16x16.NavigateForward.png NavigationIcons\Icons.16x16.NavigateForward.png
@ -555,11 +562,6 @@ ClassBrowserIcons\Icons.16x16.NameSpace.png
ClassBrowserIcons\Icons.16x16.Operator.png ClassBrowserIcons\Icons.16x16.Operator.png
ClassBrowserIcons\Icons.16x16.Parameter.png ClassBrowserIcons\Icons.16x16.Parameter.png
ClassBrowserIcons\Icons.16x16.Struct.png ClassBrowserIcons\Icons.16x16.Struct.png
ClassBrowserIcons\Icons.16x16.Workspace.png
ClassBrowserIcons\Icons.16x16.Assembly.png
ClassBrowserIcons\Icons.16x16.Module.png
ClassBrowserIcons\Icons.16x16.AssemblyFromFile.png
ClassBrowserIcons\Icons.16x16.AssemblyFromGAC.png
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Left original (other source than Fugue Iconlibrary) Left original (other source than Fugue Iconlibrary)

3
data/resources/image/BitmapResources/BitmapResources.res

@ -86,6 +86,7 @@ Icons.16x16.Debug.Continue = DebuggerIcons\Icons.16x16.Debug.Continue.png
Icons.16x16.Debug.StepOver = DebuggerIcons\Icons.16x16.Debug.StepOver.png Icons.16x16.Debug.StepOver = DebuggerIcons\Icons.16x16.Debug.StepOver.png
Icons.16x16.Debug.StepInto = DebuggerIcons\Icons.16x16.Debug.StepInto.png Icons.16x16.Debug.StepInto = DebuggerIcons\Icons.16x16.Debug.StepInto.png
Icons.16x16.Debug.StepOut = DebuggerIcons\Icons.16x16.Debug.StepOut.png Icons.16x16.Debug.StepOut = DebuggerIcons\Icons.16x16.Debug.StepOut.png
Icons.16x16.Debug.Assembly = DebuggerIcons\Icons.16x16.Debug.Assembly.png
# TestRunner # TestRunner
Icons.16x16.TestRunner.Yellow = BitmapResources-data\Icons.16x16.TestRunner.Yellow.png Icons.16x16.TestRunner.Yellow = BitmapResources-data\Icons.16x16.TestRunner.Yellow.png
@ -297,7 +298,9 @@ Icons.16x16.AssemblyFromGAC = ClassBrowserIcons\Icons.16x16.AssemblyFromGA
Icons.16x16.Workspace = ClassBrowserIcons\Icons.16x16.Workspace.png Icons.16x16.Workspace = ClassBrowserIcons\Icons.16x16.Workspace.png
Icons.16x16.Assembly = ClassBrowserIcons\Icons.16x16.Assembly.png Icons.16x16.Assembly = ClassBrowserIcons\Icons.16x16.Assembly.png
Icons.16x16.AssemblyError = ClassBrowserIcons\Icons.16x16.AssemblyError.png
Icons.16x16.Module = ClassBrowserIcons\Icons.16x16.Module.png Icons.16x16.Module = ClassBrowserIcons\Icons.16x16.Module.png
Icons.16x16.ModuleError = ClassBrowserIcons\Icons.16x16.ModuleError.png
Icons.16x16.NameSpace = ClassBrowserIcons\Icons.16x16.NameSpace.png Icons.16x16.NameSpace = ClassBrowserIcons\Icons.16x16.NameSpace.png
Icons.16x16.Literal = ClassBrowserIcons\Icons.16x16.Literal.png Icons.16x16.Literal = ClassBrowserIcons\Icons.16x16.Literal.png
Icons.16x16.Reference = ClassBrowserIcons\Icons.16x16.Reference.png Icons.16x16.Reference = ClassBrowserIcons\Icons.16x16.Reference.png

BIN
data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.AssemblyError.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

BIN
data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.AssemblyFromFile.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 B

After

Width:  |  Height:  |  Size: 777 B

BIN
data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.AssemblyFromGAC.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 729 B

BIN
data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.Module.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 727 B

After

Width:  |  Height:  |  Size: 749 B

BIN
data/resources/image/BitmapResources/ClassBrowserIcons/Icons.16x16.ModuleError.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

BIN
data/resources/image/BitmapResources/DebuggerIcons/Icons.16x16.Debug.Assembly.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

7
src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs

@ -106,7 +106,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
public override object Icon { public override object Icon {
get { get {
return IconService.GetImageSource("Icons.16x16.Debug.Start"); return IconService.GetImageSource("Icons.16x16.Debug.Assembly");
} }
} }
} }
@ -135,6 +135,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
} }
} }
public override void ShowContextMenu()
{
// Don't show context menu as for usual AssemblyTreeNodes.
}
static IAssemblyModel CreateAssemblyModel(Module module) static IAssemblyModel CreateAssemblyModel(Module module)
{ {
// references?? // references??

4
src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj

@ -191,9 +191,7 @@
<Page Include="Src\View\AddInsView.xaml" /> <Page Include="Src\View\AddInsView.xaml" />
<Page Include="Src\View\LicenseAcceptanceView.xaml" /> <Page Include="Src\View\LicenseAcceptanceView.xaml" />
<Page Include="Src\View\PagedResultsView.xaml" /> <Page Include="Src\View\PagedResultsView.xaml" />
<Page Include="Src\View\PackageRepositoriesView.xaml"> <Page Include="Src\View\PackageRepositoriesView.xaml" />
<DependentUpon>PagedResultsView.xaml</DependentUpon>
</Page>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> </Project>

16
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CaretNavigationTests.cs

@ -113,5 +113,21 @@ namespace ICSharpCode.AvalonEdit.Utils
Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder)); Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder));
Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder)); Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder));
} }
[Test]
public void CombiningMark()
{
string str = " x͆ ";
Assert.AreEqual(3, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 3, CaretPositioningMode.Normal));
}
[Test]
public void StackedCombiningMark()
{
string str = " x͆͆͆͆ ";
Assert.AreEqual(6, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 6, CaretPositioningMode.Normal));
}
} }
} }

97
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs

@ -14,7 +14,7 @@ namespace ICSharpCode.AvalonEdit.Document
public enum CaretPositioningMode public enum CaretPositioningMode
{ {
/// <summary> /// <summary>
/// Normal positioning (stop at every caret position) /// Normal positioning (stop after every grapheme)
/// </summary> /// </summary>
Normal, Normal,
/// <summary> /// <summary>
@ -32,7 +32,12 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary> /// <summary>
/// Stop only on word borders, and anywhere in the middle of symbols. /// Stop only on word borders, and anywhere in the middle of symbols.
/// </summary> /// </summary>
WordBorderOrSymbol WordBorderOrSymbol,
/// <summary>
/// Stop between every Unicode codepoint, even within the same grapheme.
/// This is used to implement deleting the previous grapheme when Backspace is pressed.
/// </summary>
EveryCodepoint
} }
/// <summary> /// <summary>
@ -199,37 +204,43 @@ namespace ICSharpCode.AvalonEdit.Document
{ {
if (c == '\r' || c == '\n') if (c == '\r' || c == '\n')
return CharacterClass.LineTerminator; return CharacterClass.LineTerminator;
else if (char.IsWhiteSpace(c)) if (c == '_')
return CharacterClass.Whitespace;
else if (char.IsLetterOrDigit(c) || c == '_')
return CharacterClass.IdentifierPart; return CharacterClass.IdentifierPart;
else return GetCharacterClass(char.GetUnicodeCategory(c));
return CharacterClass.Other;
} }
static CharacterClass GetCharacterClass(char highSurrogate, char lowSurrogate) static CharacterClass GetCharacterClass(char highSurrogate, char lowSurrogate)
{ {
if (char.IsSurrogatePair(highSurrogate, lowSurrogate)) { if (char.IsSurrogatePair(highSurrogate, lowSurrogate)) {
switch (char.GetUnicodeCategory(highSurrogate.ToString() + lowSurrogate.ToString(), 0)) { return GetCharacterClass(char.GetUnicodeCategory(highSurrogate.ToString() + lowSurrogate.ToString(), 0));
case UnicodeCategory.SpaceSeparator:
case UnicodeCategory.LineSeparator:
case UnicodeCategory.ParagraphSeparator:
return CharacterClass.Whitespace;
case UnicodeCategory.UppercaseLetter:
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.TitlecaseLetter:
case UnicodeCategory.ModifierLetter:
case UnicodeCategory.OtherLetter:
case UnicodeCategory.DecimalDigitNumber:
return CharacterClass.IdentifierPart;
default:
return CharacterClass.Other;
}
} else { } else {
// malformed surrogate pair // malformed surrogate pair
return CharacterClass.Other; return CharacterClass.Other;
} }
} }
static CharacterClass GetCharacterClass(UnicodeCategory c)
{
switch (c) {
case UnicodeCategory.SpaceSeparator:
case UnicodeCategory.LineSeparator:
case UnicodeCategory.ParagraphSeparator:
return CharacterClass.Whitespace;
case UnicodeCategory.UppercaseLetter:
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.TitlecaseLetter:
case UnicodeCategory.ModifierLetter:
case UnicodeCategory.OtherLetter:
case UnicodeCategory.DecimalDigitNumber:
return CharacterClass.IdentifierPart;
case UnicodeCategory.NonSpacingMark:
case UnicodeCategory.SpacingCombiningMark:
case UnicodeCategory.EnclosingMark:
return CharacterClass.CombiningMark;
default:
return CharacterClass.Other;
}
}
#endregion #endregion
#region GetNextCaretPosition #region GetNextCaretPosition
@ -251,13 +262,16 @@ namespace ICSharpCode.AvalonEdit.Document
{ {
if (textSource == null) if (textSource == null)
throw new ArgumentNullException("textSource"); throw new ArgumentNullException("textSource");
if (mode != CaretPositioningMode.Normal switch (mode) {
&& mode != CaretPositioningMode.WordBorder case CaretPositioningMode.Normal:
&& mode != CaretPositioningMode.WordStart case CaretPositioningMode.EveryCodepoint:
&& mode != CaretPositioningMode.WordBorderOrSymbol case CaretPositioningMode.WordBorder:
&& mode != CaretPositioningMode.WordStartOrSymbol) case CaretPositioningMode.WordBorderOrSymbol:
{ case CaretPositioningMode.WordStart:
throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, "mode"); case CaretPositioningMode.WordStartOrSymbol:
break; // OK
default:
throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, "mode");
} }
if (direction != LogicalDirection.Backward if (direction != LogicalDirection.Backward
&& direction != LogicalDirection.Forward) && direction != LogicalDirection.Forward)
@ -267,7 +281,7 @@ namespace ICSharpCode.AvalonEdit.Document
int textLength = textSource.TextLength; int textLength = textSource.TextLength;
if (textLength <= 0) { if (textLength <= 0) {
// empty document? has a normal caret position at 0, though no word borders // empty document? has a normal caret position at 0, though no word borders
if (mode == CaretPositioningMode.Normal) { if (IsNormal(mode)) {
if (offset > 0 && direction == LogicalDirection.Backward) return 0; if (offset > 0 && direction == LogicalDirection.Backward) return 0;
if (offset < 0 && direction == LogicalDirection.Forward) return 0; if (offset < 0 && direction == LogicalDirection.Forward) return 0;
} }
@ -286,14 +300,14 @@ namespace ICSharpCode.AvalonEdit.Document
if (nextPos == 0) { if (nextPos == 0) {
// at the document start, there's only a word border // at the document start, there's only a word border
// if the first character is not whitespace // if the first character is not whitespace
if (mode == CaretPositioningMode.Normal || !char.IsWhiteSpace(textSource.GetCharAt(0))) if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(0)))
return nextPos; return nextPos;
} else if (nextPos == textLength) { } else if (nextPos == textLength) {
// at the document end, there's never a word start // at the document end, there's never a word start
if (mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol) { if (mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol) {
// at the document end, there's only a word border // at the document end, there's only a word border
// if the last character is not whitespace // if the last character is not whitespace
if (mode == CaretPositioningMode.Normal || !char.IsWhiteSpace(textSource.GetCharAt(textLength - 1))) if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(textLength - 1)))
return nextPos; return nextPos;
} }
} else { } else {
@ -320,9 +334,19 @@ namespace ICSharpCode.AvalonEdit.Document
} }
} }
static bool IsNormal(CaretPositioningMode mode)
{
return mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint;
}
static bool StopBetweenCharacters(CaretPositioningMode mode, CharacterClass charBefore, CharacterClass charAfter) static bool StopBetweenCharacters(CaretPositioningMode mode, CharacterClass charBefore, CharacterClass charAfter)
{ {
// Stop after every character in normal mode if (mode == CaretPositioningMode.EveryCodepoint)
return true;
// Don't stop in the middle of a grapheme
if (charAfter == CharacterClass.CombiningMark)
return false;
// Stop after every grapheme in normal mode
if (mode == CaretPositioningMode.Normal) if (mode == CaretPositioningMode.Normal)
return true; return true;
if (charBefore == charAfter) { if (charBefore == charAfter) {
@ -370,6 +394,11 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary> /// <summary>
/// The character is line terminator (\r or \n). /// The character is line terminator (\r or \n).
/// </summary> /// </summary>
LineTerminator LineTerminator,
/// <summary>
/// The character is a unicode combining mark that modifies the previous character.
/// Corresponds to the Unicode designations "Mn", "Mc" and "Me".
/// </summary>
CombiningMark
} }
} }

200
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs

@ -15,6 +15,24 @@ using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Editing namespace ICSharpCode.AvalonEdit.Editing
{ {
enum CaretMovementType
{
None,
CharLeft,
CharRight,
Backspace,
WordLeft,
WordRight,
LineUp,
LineDown,
PageUp,
PageDown,
LineStart,
LineEnd,
DocumentStart,
DocumentEnd
}
static class CaretNavigationCommandHandler static class CaretNavigationCommandHandler
{ {
/// <summary> /// <summary>
@ -102,22 +120,6 @@ namespace ICSharpCode.AvalonEdit.Editing
return target as TextArea; return target as TextArea;
} }
enum CaretMovementType
{
CharLeft,
CharRight,
WordLeft,
WordRight,
LineUp,
LineDown,
PageUp,
PageDown,
LineStart,
LineEnd,
DocumentStart,
DocumentEnd
}
static ExecutedRoutedEventHandler OnMoveCaret(CaretMovementType direction) static ExecutedRoutedEventHandler OnMoveCaret(CaretMovementType direction)
{ {
return (target, args) => { return (target, args) => {
@ -140,8 +142,7 @@ namespace ICSharpCode.AvalonEdit.Editing
TextViewPosition oldPosition = textArea.Caret.Position; TextViewPosition oldPosition = textArea.Caret.Position;
MoveCaret(textArea, direction); MoveCaret(textArea, direction);
textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position); textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position);
if (!textArea.Document.IsInUpdate) // if we're inside a larger update (e.g. called by EditingCommandHandler.OnDelete()), avoid calculating the caret rectangle now textArea.Caret.BringCaretToView();
textArea.Caret.BringCaretToView();
} }
}; };
} }
@ -172,43 +173,55 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
#region Caret movement #region Caret movement
static void MoveCaret(TextArea textArea, CaretMovementType direction) internal static void MoveCaret(TextArea textArea, CaretMovementType direction)
{ {
DocumentLine caretLine = textArea.Document.GetLineByNumber(textArea.Caret.Line); double desiredXPos = textArea.Caret.DesiredXPos;
VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(caretLine); textArea.Caret.Position = GetNewCaretPosition(textArea.TextView, textArea.Caret.Position, direction, textArea.Selection.EnableVirtualSpace, ref desiredXPos);
TextViewPosition caretPosition = textArea.Caret.Position; textArea.Caret.DesiredXPos = desiredXPos;
}
internal static TextViewPosition GetNewCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, bool enableVirtualSpace, ref double desiredXPos)
{
switch (direction) {
case CaretMovementType.None:
return caretPosition;
case CaretMovementType.DocumentStart:
desiredXPos = double.NaN;
return new TextViewPosition(0, 0);
case CaretMovementType.DocumentEnd:
desiredXPos = double.NaN;
return new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength));
}
DocumentLine caretLine = textView.Document.GetLineByNumber(caretPosition.Line);
VisualLine visualLine = textView.GetOrConstructVisualLine(caretLine);
TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn, caretPosition.IsAtEndOfLine); TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn, caretPosition.IsAtEndOfLine);
switch (direction) { switch (direction) {
case CaretMovementType.CharLeft: case CaretMovementType.CharLeft:
MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.Normal); desiredXPos = double.NaN;
break; return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.Normal, enableVirtualSpace);
case CaretMovementType.Backspace:
desiredXPos = double.NaN;
return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.EveryCodepoint, enableVirtualSpace);
case CaretMovementType.CharRight: case CaretMovementType.CharRight:
MoveCaretRight(textArea, caretPosition, visualLine, CaretPositioningMode.Normal); desiredXPos = double.NaN;
break; return GetNextCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.Normal, enableVirtualSpace);
case CaretMovementType.WordLeft: case CaretMovementType.WordLeft:
MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.WordStart); desiredXPos = double.NaN;
break; return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.WordStart, enableVirtualSpace);
case CaretMovementType.WordRight: case CaretMovementType.WordRight:
MoveCaretRight(textArea, caretPosition, visualLine, CaretPositioningMode.WordStart); desiredXPos = double.NaN;
break; return GetNextCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.WordStart, enableVirtualSpace);
case CaretMovementType.LineUp: case CaretMovementType.LineUp:
case CaretMovementType.LineDown: case CaretMovementType.LineDown:
case CaretMovementType.PageUp: case CaretMovementType.PageUp:
case CaretMovementType.PageDown: case CaretMovementType.PageDown:
MoveCaretUpDown(textArea, direction, visualLine, textLine, caretPosition.VisualColumn); return GetUpDownCaretPosition(textView, caretPosition, direction, visualLine, textLine, enableVirtualSpace, ref desiredXPos);
break;
case CaretMovementType.DocumentStart:
SetCaretPosition(textArea, 0, 0);
break;
case CaretMovementType.DocumentEnd:
SetCaretPosition(textArea, -1, textArea.Document.TextLength);
break;
case CaretMovementType.LineStart: case CaretMovementType.LineStart:
MoveCaretToStartOfLine(textArea, visualLine, textLine); desiredXPos = double.NaN;
break; return GetStartOfLineCaretPosition(caretPosition.VisualColumn, visualLine, textLine, enableVirtualSpace);
case CaretMovementType.LineEnd: case CaretMovementType.LineEnd:
MoveCaretToEndOfLine(textArea, visualLine, textLine); desiredXPos = double.NaN;
break; return GetEndOfLineCaretPosition(visualLine, textLine);
default: default:
throw new NotSupportedException(direction.ToString()); throw new NotSupportedException(direction.ToString());
} }
@ -216,81 +229,80 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion #endregion
#region Home/End #region Home/End
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine) static TextViewPosition GetStartOfLineCaretPosition(int oldVC, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace)
{ {
int newVC = visualLine.GetTextLineVisualStartColumn(textLine); int newVC = visualLine.GetTextLineVisualStartColumn(textLine);
if (newVC == 0) if (newVC == 0)
newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, textArea.Selection.EnableVirtualSpace); newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, enableVirtualSpace);
if (newVC < 0) if (newVC < 0)
throw ThrowUtil.NoValidCaretPosition(); throw ThrowUtil.NoValidCaretPosition();
// when the caret is already at the start of the text, jump to start before whitespace // when the caret is already at the start of the text, jump to start before whitespace
if (newVC == textArea.Caret.VisualColumn) if (newVC == oldVC)
newVC = 0; newVC = 0;
int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); return visualLine.GetTextViewPosition(newVC);
SetCaretPosition(textArea, newVC, offset);
} }
static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine) static TextViewPosition GetEndOfLineCaretPosition(VisualLine visualLine, TextLine textLine)
{ {
int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength; int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength;
int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); TextViewPosition pos = visualLine.GetTextViewPosition(newVC);
SetCaretPosition(textArea, newVC, offset, isAtEndOfLine: true); pos.IsAtEndOfLine = true;
return pos;
} }
#endregion #endregion
#region By-character / By-word movement #region By-character / By-word movement
static void MoveCaretRight(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode) static TextViewPosition GetNextCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
{ {
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace); int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, enableVirtualSpace);
if (pos >= 0) { if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset); return visualLine.GetTextViewPosition(pos);
} else { } else {
// move to start of next line // move to start of next line
DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine; DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
if (nextDocumentLine != null) { if (nextDocumentLine != null) {
VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine); VisualLine nextLine = textView.GetOrConstructVisualLine(nextDocumentLine);
pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace); pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, enableVirtualSpace);
if (pos < 0) if (pos < 0)
throw ThrowUtil.NoValidCaretPosition(); throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset); return nextLine.GetTextViewPosition(pos);
} else { } else {
// at end of document // at end of document
Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textArea.Document.TextLength); Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textView.Document.TextLength);
SetCaretPosition(textArea, -1, textArea.Document.TextLength); return new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength));
} }
} }
} }
static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode) static TextViewPosition GetPrevCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
{ {
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace); int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, enableVirtualSpace);
if (pos >= 0) { if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset); return visualLine.GetTextViewPosition(pos);
} else { } else {
// move to end of previous line // move to end of previous line
DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine; DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
if (previousDocumentLine != null) { if (previousDocumentLine != null) {
VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine); VisualLine previousLine = textView.GetOrConstructVisualLine(previousDocumentLine);
pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace); pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, enableVirtualSpace);
if (pos < 0) if (pos < 0)
throw ThrowUtil.NoValidCaretPosition(); throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset); return previousLine.GetTextViewPosition(pos);
} else { } else {
// at start of document // at start of document
Debug.Assert(visualLine.FirstDocumentLine.Offset == 0); Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
SetCaretPosition(textArea, 0, 0); return new TextViewPosition(0, 0);
} }
} }
} }
#endregion #endregion
#region Line+Page up/down #region Line+Page up/down
static void MoveCaretUpDown(TextArea textArea, CaretMovementType direction, VisualLine visualLine, TextLine textLine, int caretVisualColumn) static TextViewPosition GetUpDownCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace, ref double xPos)
{ {
// moving up/down happens using the desired visual X position // moving up/down happens using the desired visual X position
double xPos = textArea.Caret.DesiredXPos;
if (double.IsNaN(xPos)) if (double.IsNaN(xPos))
xPos = visualLine.GetTextLineVisualXPosition(textLine, caretVisualColumn); xPos = visualLine.GetTextLineVisualXPosition(textLine, caretPosition.VisualColumn);
// now find the TextLine+VisualLine where the caret will end up in // now find the TextLine+VisualLine where the caret will end up in
VisualLine targetVisualLine = visualLine; VisualLine targetVisualLine = visualLine;
TextLine targetLine; TextLine targetLine;
@ -304,8 +316,8 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textLineIndex > 0) { if (textLineIndex > 0) {
targetLine = visualLine.TextLines[textLineIndex - 1]; targetLine = visualLine.TextLines[textLineIndex - 1];
} else if (prevLineNumber >= 1) { } else if (prevLineNumber >= 1) {
DocumentLine prevLine = textArea.Document.GetLineByNumber(prevLineNumber); DocumentLine prevLine = textView.Document.GetLineByNumber(prevLineNumber);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(prevLine); targetVisualLine = textView.GetOrConstructVisualLine(prevLine);
targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1]; targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1];
} else { } else {
targetLine = null; targetLine = null;
@ -319,9 +331,9 @@ namespace ICSharpCode.AvalonEdit.Editing
int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1; int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1;
if (textLineIndex < visualLine.TextLines.Count - 1) { if (textLineIndex < visualLine.TextLines.Count - 1) {
targetLine = visualLine.TextLines[textLineIndex + 1]; targetLine = visualLine.TextLines[textLineIndex + 1];
} else if (nextLineNumber <= textArea.Document.LineCount) { } else if (nextLineNumber <= textView.Document.LineCount) {
DocumentLine nextLine = textArea.Document.GetLineByNumber(nextLineNumber); DocumentLine nextLine = textView.Document.GetLineByNumber(nextLineNumber);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(nextLine); targetVisualLine = textView.GetOrConstructVisualLine(nextLine);
targetLine = targetVisualLine.TextLines[0]; targetLine = targetVisualLine.TextLines[0];
} else { } else {
targetLine = null; targetLine = null;
@ -334,11 +346,11 @@ namespace ICSharpCode.AvalonEdit.Editing
// Page up/down: find the target line using its visual position // Page up/down: find the target line using its visual position
double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle); double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle);
if (direction == CaretMovementType.PageUp) if (direction == CaretMovementType.PageUp)
yPos -= textArea.TextView.RenderSize.Height; yPos -= textView.RenderSize.Height;
else else
yPos += textArea.TextView.RenderSize.Height; yPos += textView.RenderSize.Height;
DocumentLine newLine = textArea.TextView.GetDocumentLineByVisualTop(yPos); DocumentLine newLine = textView.GetDocumentLineByVisualTop(yPos);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(newLine); targetVisualLine = textView.GetOrConstructVisualLine(newLine);
targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos); targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos);
break; break;
} }
@ -347,30 +359,18 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
if (targetLine != null) { if (targetLine != null) {
double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle); double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle);
int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), textArea.Selection.EnableVirtualSpace); int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), enableVirtualSpace);
SetCaretPosition(textArea, targetVisualLine, targetLine, newVisualColumn, false);
textArea.Caret.DesiredXPos = xPos; // prevent wrapping to the next line; TODO: could 'IsAtEnd' help here?
} int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine);
} if (newVisualColumn >= targetLineStartCol + targetLine.Length) {
#endregion if (newVisualColumn <= targetVisualLine.VisualLength)
newVisualColumn = targetLineStartCol + targetLine.Length - 1;
#region SetCaretPosition }
static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine, return targetVisualLine.GetTextViewPosition(newVisualColumn);
int newVisualColumn, bool allowWrapToNextLine) } else {
{ return caretPosition;
int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine);
if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length) {
if (newVisualColumn <= targetVisualLine.VisualLength)
newVisualColumn = targetLineStartCol + targetLine.Length - 1;
} }
int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset;
SetCaretPosition(textArea, newVisualColumn, newOffset);
}
static void SetCaretPosition(TextArea textArea, int newVisualColumn, int newOffset, bool isAtEndOfLine = false)
{
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(newOffset), newVisualColumn) { IsAtEndOfLine = isAtEndOfLine };
textArea.Caret.DesiredXPos = double.NaN;
} }
#endregion #endregion
} }

48
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -46,12 +46,12 @@ namespace ICSharpCode.AvalonEdit.Editing
static EditingCommandHandler() static EditingCommandHandler()
{ {
CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDelete(ApplicationCommands.NotACommand), CanDelete)); CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDelete(CaretMovementType.None), CanDelete));
AddBinding(EditingCommands.Delete, ModifierKeys.None, Key.Delete, OnDelete(EditingCommands.SelectRightByCharacter)); AddBinding(EditingCommands.Delete, ModifierKeys.None, Key.Delete, OnDelete(CaretMovementType.CharRight));
AddBinding(EditingCommands.DeleteNextWord, ModifierKeys.Control, Key.Delete, OnDelete(EditingCommands.SelectRightByWord)); AddBinding(EditingCommands.DeleteNextWord, ModifierKeys.Control, Key.Delete, OnDelete(CaretMovementType.WordRight));
AddBinding(EditingCommands.Backspace, ModifierKeys.None, Key.Back, OnDelete(EditingCommands.SelectLeftByCharacter)); AddBinding(EditingCommands.Backspace, ModifierKeys.None, Key.Back, OnDelete(CaretMovementType.Backspace));
InputBindings.Add(TextAreaDefaultInputHandler.CreateFrozenKeyBinding(EditingCommands.Backspace, ModifierKeys.Shift, Key.Back)); // make Shift-Backspace do the same as plain backspace InputBindings.Add(TextAreaDefaultInputHandler.CreateFrozenKeyBinding(EditingCommands.Backspace, ModifierKeys.Shift, Key.Back)); // make Shift-Backspace do the same as plain backspace
AddBinding(EditingCommands.DeletePreviousWord, ModifierKeys.Control, Key.Back, OnDelete(EditingCommands.SelectLeftByWord)); AddBinding(EditingCommands.DeletePreviousWord, ModifierKeys.Control, Key.Back, OnDelete(CaretMovementType.WordLeft));
AddBinding(EditingCommands.EnterParagraphBreak, ModifierKeys.None, Key.Enter, OnEnter); AddBinding(EditingCommands.EnterParagraphBreak, ModifierKeys.None, Key.Enter, OnEnter);
AddBinding(EditingCommands.EnterLineBreak, ModifierKeys.Shift, Key.Enter, OnEnter); AddBinding(EditingCommands.EnterLineBreak, ModifierKeys.Shift, Key.Enter, OnEnter);
AddBinding(EditingCommands.TabForward, ModifierKeys.None, Key.Tab, OnTab); AddBinding(EditingCommands.TabForward, ModifierKeys.None, Key.Tab, OnTab);
@ -225,34 +225,24 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion #endregion
#region Delete #region Delete
static ExecutedRoutedEventHandler OnDelete(RoutedUICommand selectingCommand) static ExecutedRoutedEventHandler OnDelete(CaretMovementType caretMovement)
{ {
return (target, args) => { return (target, args) => {
TextArea textArea = GetTextArea(target); TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) { if (textArea != null && textArea.Document != null) {
// call BeginUpdate before running the 'selectingCommand' if (textArea.Selection.IsEmpty) {
// so that undoing the delete does not select the deleted character TextViewPosition startPos = textArea.Caret.Position;
using (textArea.Document.RunUpdate()) { bool enableVirtualSpace = textArea.Options.EnableVirtualSpace;
if (textArea.Selection.IsEmpty) { // When pressing delete; don't move the caret further into virtual space - instead delete the newline
TextViewPosition oldCaretPosition = textArea.Caret.Position; if (caretMovement == CaretMovementType.CharRight)
if (textArea.Caret.IsInVirtualSpace && selectingCommand == EditingCommands.SelectRightByCharacter) enableVirtualSpace = false;
EditingCommands.SelectRightByWord.Execute(args.Parameter, textArea); double desiredXPos = textArea.Caret.DesiredXPos;
else TextViewPosition endPos = CaretNavigationCommandHandler.GetNewCaretPosition(
selectingCommand.Execute(args.Parameter, textArea); textArea.TextView, startPos, caretMovement, enableVirtualSpace, ref desiredXPos);
bool hasSomethingDeletable = false; // Don't select the text to be deleted; just reuse the ReplaceSelectionWithText logic
foreach (ISegment s in textArea.Selection.Segments) { var sel = new SimpleSelection(textArea, startPos, endPos);
if (textArea.GetDeletableSegments(s).Length > 0) { sel.ReplaceSelectionWithText(string.Empty);
hasSomethingDeletable = true; } else {
break;
}
}
if (!hasSomethingDeletable) {
// If nothing in the selection is deletable; then reset caret+selection
// to the previous value. This prevents the caret from moving through read-only sections.
textArea.Caret.Position = oldCaretPosition;
textArea.ClearSelection();
}
}
textArea.RemoveSelectedText(); textArea.RemoveSelectedText();
} }
textArea.Caret.BringCaretToView(); textArea.Caret.BringCaretToView();

16
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs

@ -55,10 +55,16 @@ namespace ICSharpCode.AvalonEdit.Editing
if (segmentsToDelete[i].Offset == SurroundingSegment.Offset && segmentsToDelete[i].Length == SurroundingSegment.Length) { if (segmentsToDelete[i].Offset == SurroundingSegment.Offset && segmentsToDelete[i].Length == SurroundingSegment.Length) {
newText = AddSpacesIfRequired(newText, start, end); newText = AddSpacesIfRequired(newText, start, end);
} }
int vc = textArea.Caret.VisualColumn; if (string.IsNullOrEmpty(newText)) {
textArea.Caret.Offset = segmentsToDelete[i].EndOffset; // place caret at the beginning of the selection
if (string.IsNullOrEmpty(newText)) if (start.CompareTo(end) <= 0)
textArea.Caret.VisualColumn = vc; textArea.Caret.Position = start;
else
textArea.Caret.Position = end;
} else {
// place caret so that it ends up behind the new text
textArea.Caret.Offset = segmentsToDelete[i].EndOffset;
}
textArea.Document.Replace(segmentsToDelete[i], newText); textArea.Document.Replace(segmentsToDelete[i], newText);
} else { } else {
textArea.Document.Remove(segmentsToDelete[i]); textArea.Document.Remove(segmentsToDelete[i]);
@ -100,7 +106,7 @@ namespace ICSharpCode.AvalonEdit.Editing
/// <inheritdoc/> /// <inheritdoc/>
public override bool IsEmpty { public override bool IsEmpty {
get { return startOffset == endOffset; } get { return startOffset == endOffset && start.VisualColumn == end.VisualColumn; }
} }
/// <inheritdoc/> /// <inheritdoc/>

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs

@ -111,7 +111,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode) public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
{ {
if (mode == CaretPositioningMode.Normal) if (mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint)
return base.GetNextCaretPosition(visualColumn, direction, mode); return base.GetNextCaretPosition(visualColumn, direction, mode);
else else
return -1; return -1;
@ -146,7 +146,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode) public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
{ {
if (mode == CaretPositioningMode.Normal) if (mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint)
return base.GetNextCaretPosition(visualColumn, direction, mode); return base.GetNextCaretPosition(visualColumn, direction, mode);
else else
return -1; return -1;

13
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs

@ -548,6 +548,15 @@ namespace ICSharpCode.AvalonEdit.Rendering
return ch.FirstCharacterIndex; return ch.FirstCharacterIndex;
} }
/// <summary>
/// Gets the text view position from the specified visual column.
/// </summary>
public TextViewPosition GetTextViewPosition(int visualColumn)
{
int documentOffset = GetRelativeOffset(visualColumn) + this.FirstDocumentLine.Offset;
return new TextViewPosition(this.Document.GetLocation(documentOffset), visualColumn);
}
/// <summary> /// <summary>
/// Gets the text view position from the specified visual position. /// Gets the text view position from the specified visual position.
/// If the position is within a character, it is rounded to the next character boundary. /// If the position is within a character, it is rounded to the next character boundary.
@ -690,12 +699,12 @@ namespace ICSharpCode.AvalonEdit.Rendering
static bool HasStopsInVirtualSpace(CaretPositioningMode mode) static bool HasStopsInVirtualSpace(CaretPositioningMode mode)
{ {
return mode == CaretPositioningMode.Normal; return mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint;
} }
static bool HasImplicitStopAtLineStart(CaretPositioningMode mode) static bool HasImplicitStopAtLineStart(CaretPositioningMode mode)
{ {
return mode == CaretPositioningMode.Normal; return mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint;
} }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "mode", [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "mode",

27
src/Main/Base/Project/Dom/ClassBrowser/AssemblyLoadErrorTreeNode.cs

@ -0,0 +1,27 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.Core.Presentation;
using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
public class AssemblyLoadErrorTreeNode : SharpTreeNode
{
public override object Text {
get {
return "(Assembly not loadable)";
}
}
public override object Icon {
get {
return null;
}
}
}
}

26
src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.Core.Presentation;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
@ -35,6 +36,17 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
} }
} }
protected override void LoadChildren()
{
Children.Clear();
if (model.Context.IsValid) {
base.LoadChildren();
} else {
// This assembly could not be loaded correctly, add sub-node with error text
Children.Add(new AssemblyLoadErrorTreeNode());
}
}
public override object Text { public override object Text {
get { get {
return model.AssemblyName; return model.AssemblyName;
@ -43,7 +55,19 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
public override object Icon { public override object Icon {
get { get {
return SD.ResourceService.GetImageSource("Icons.16x16.Assembly"); if (model.Context.IsValid) {
return SD.ResourceService.GetImageSource("Icons.16x16.Assembly");
} else {
return SD.ResourceService.GetImageSource("Icons.16x16.AssemblyError");
}
}
}
public override void ShowContextMenu()
{
var assemblyModel = this.Model as IAssemblyModel;
if (assemblyModel != null) {
var ctx = MenuService.ShowContextMenu(null, assemblyModel, "/SharpDevelop/Pads/ClassBrowser/AssemblyContextMenu");
} }
} }
} }

4
src/Main/Base/Project/Dom/ClassBrowser/TypeDefinitionTreeNode.cs

@ -3,10 +3,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Policy;
using ICSharpCode.Core.Presentation; using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using ICSharpCode.SharpDevelop.Dom;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{ {
@ -48,7 +50,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
protected override IModelCollection<object> ModelChildren { protected override IModelCollection<object> ModelChildren {
get { get {
return definition.Members; return definition.NestedTypes.Concat<object>(definition.Members);
} }
} }

25
src/Main/Base/Project/Dom/ClassBrowser/WorkspaceTreeNode.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
@ -13,7 +14,25 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
/// </summary> /// </summary>
public class WorkspaceTreeNode : ModelCollectionTreeNode public class WorkspaceTreeNode : ModelCollectionTreeNode
{ {
class WorkspaceChildComparer : IComparer<SharpTreeNode>
{
IComparer<string> stringComparer = StringComparer.OrdinalIgnoreCase;
public int Compare(SharpTreeNode x, SharpTreeNode y)
{
// Solution node has precedence over other nodes
if ((x is SolutionTreeNode) && !(y is SolutionTreeNode))
return -1;
if (!(x is SolutionTreeNode) && (y is SolutionTreeNode))
return 1;
// Both nodes are solutions or not solutions, compare their Text property
return stringComparer.Compare(x.Text.ToString(), y.Text.ToString());
}
}
WorkspaceModel workspace; WorkspaceModel workspace;
protected static readonly IComparer<SharpTreeNode> ChildNodeComparer = new WorkspaceChildComparer();
public IMutableModelCollection<SharpTreeNode> SpecialNodes { public IMutableModelCollection<SharpTreeNode> SpecialNodes {
get { return workspace.SpecialNodes; } get { return workspace.SpecialNodes; }
@ -40,7 +59,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
} }
protected override IComparer<SharpTreeNode> NodeComparer { protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; } get { return ChildNodeComparer; }
} }
public override object Text { public override object Text {
@ -62,7 +81,9 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
protected override void InsertSpecialNodes() protected override void InsertSpecialNodes()
{ {
Children.AddRange(workspace.SpecialNodes); foreach (var node in workspace.SpecialNodes) {
Children.OrderedInsert(node, ChildNodeComparer);
}
} }
void SpecialNodesModelCollectionChanged(IReadOnlyCollection<SharpTreeNode> removedItems, IReadOnlyCollection<SharpTreeNode> addedItems) void SpecialNodesModelCollectionChanged(IReadOnlyCollection<SharpTreeNode> removedItems, IReadOnlyCollection<SharpTreeNode> addedItems)

11
src/Main/Base/Project/Dom/IAssemblyModel.cs

@ -42,6 +42,11 @@ namespace ICSharpCode.SharpDevelop.Dom
/// This always is the namespace without a name - it's unrelated to the 'root namespace' project setting. /// This always is the namespace without a name - it's unrelated to the 'root namespace' project setting.
/// </remarks> /// </remarks>
INamespaceModel RootNamespace { get; } INamespaceModel RootNamespace { get; }
/// <summary>
/// Gets the <see cref="IEntityModelContext"/> of this assembly model.
/// </summary>
IEntityModelContext Context { get; }
} }
/// <summary> /// <summary>
@ -92,6 +97,12 @@ namespace ICSharpCode.SharpDevelop.Dom
public INamespaceModel RootNamespace { public INamespaceModel RootNamespace {
get { return EmptyNamespaceModel.Instance; } get { return EmptyNamespaceModel.Instance; }
} }
public IEntityModelContext Context {
get {
return null;
}
}
} }
} }

31
src/Main/Base/Project/Dom/IEntityModelContext.cs

@ -34,6 +34,21 @@ namespace ICSharpCode.SharpDevelop.Dom
/// Returns true if part1 is considered a better candidate for the primary part than part2. /// Returns true if part1 is considered a better candidate for the primary part than part2.
/// </summary> /// </summary>
bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2); bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2);
/// <summary>
/// Short name of current assembly.
/// </summary>
string AssemblyName { get; }
/// <summary>
/// Full path and file name of the assembly. Output assembly for projects.
/// </summary>
string Location { get; }
/// <summary>
/// Returns whether this is a valid context (based on a existing and readable definition).
/// </summary>
bool IsValid { get; }
} }
public class ProjectEntityModelContext : IEntityModelContext public class ProjectEntityModelContext : IEntityModelContext
@ -53,6 +68,10 @@ namespace ICSharpCode.SharpDevelop.Dom
get { return project.AssemblyName; } get { return project.AssemblyName; }
} }
public string Location {
get { return project.OutputAssemblyFullPath; }
}
public IProject Project { public IProject Project {
get { return project; } get { return project; }
} }
@ -66,6 +85,10 @@ namespace ICSharpCode.SharpDevelop.Dom
{ {
return EntityModelContextUtils.IsBetterPart(part1, part2, primaryCodeFileExtension); return EntityModelContextUtils.IsBetterPart(part1, part2, primaryCodeFileExtension);
} }
public bool IsValid {
get { return true; }
}
} }
public class AssemblyEntityModelContext : IEntityModelContext public class AssemblyEntityModelContext : IEntityModelContext
@ -88,6 +111,10 @@ namespace ICSharpCode.SharpDevelop.Dom
get { return mainAssembly.AssemblyName; } get { return mainAssembly.AssemblyName; }
} }
public string Location {
get { return mainAssembly.Location; }
}
public ICompilation GetCompilation() public ICompilation GetCompilation()
{ {
return compilation; return compilation;
@ -101,6 +128,10 @@ namespace ICSharpCode.SharpDevelop.Dom
public IProject Project { public IProject Project {
get { return null; } get { return null; }
} }
public bool IsValid {
get { return true; }
}
} }
public static class EntityModelContextUtils public static class EntityModelContextUtils

21
src/Main/Base/Project/ICSharpCode.SharpDevelop.addin

@ -908,7 +908,7 @@
<!-- ClassBrowser --> <!-- ClassBrowser -->
<Path name = "/SharpDevelop/Pads/ClassBrowser/Toolbar"> <Path name = "/SharpDevelop/Pads/ClassBrowser/Toolbar">
<ToolbarItem id = "Back" <!--<ToolbarItem id = "Back"
icon = "Icons.16x16.BrowserBefore" icon = "Icons.16x16.BrowserBefore"
tooltip = "${res:MainWindow.Windows.ClassBrowser.BackButton.ToolTip}" tooltip = "${res:MainWindow.Windows.ClassBrowser.BackButton.ToolTip}"
loadclasslazy = "false" loadclasslazy = "false"
@ -919,21 +919,21 @@
loadclasslazy = "false" loadclasslazy = "false"
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.ClassBrowserNavigateForward"/> class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.ClassBrowserNavigateForward"/>
<ToolbarItem id = "NavigationSeparator" type = "Separator"/> <ToolbarItem id = "NavigationSeparator" type = "Separator"/>-->
<ToolbarItem id = "OpenAssembly" <ToolbarItem id = "OpenAssembly"
type = "DropDownButton" type = "DropDownButton"
icon = "Icons.16x16.AssemblyFromFile" icon = "Icons.16x16.Assembly"
tooltip = "Open assembly"> tooltip = "Open assembly">
<MenuItem id = "OpenAssemblyFromFile" <MenuItem id = "OpenAssemblyFromFile"
icon = "Icons.16x16.AssemblyFromFile" icon = "Icons.16x16.AssemblyFromFile"
label = "Open assembly from file" label = "Open assembly from file"
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.OpenAssemblyFromFileCommand"/> class = "ICSharpCode.SharpDevelop.Dom.ClassBrowser.OpenAssemblyFromFileCommand"/>
<MenuItem id = "OpenAssemblyFromGAC" <MenuItem id = "OpenAssemblyFromGAC"
icon = "Icons.16x16.AssemblyFromGAC" icon = "Icons.16x16.AssemblyFromGAC"
label = "Open assembly from GAC" label = "Open assembly from GAC"
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.OpenAssemblyFromGACCommand"/> class = "ICSharpCode.SharpDevelop.Dom.ClassBrowser.OpenAssemblyFromGACCommand"/>
</ToolbarItem> </ToolbarItem>
<ToolbarItem id = "SelectFilter" <!--<ToolbarItem id = "SelectFilter"
type = "DropDownButton" type = "DropDownButton"
icon = "Icons.16x16.FindInFiles" icon = "Icons.16x16.FindInFiles"
tooltip = "${res:MainWindow.Windows.ClassBrowser.ClassViewSettingsButton.ToolTip}" tooltip = "${res:MainWindow.Windows.ClassBrowser.ClassViewSettingsButton.ToolTip}"
@ -968,7 +968,7 @@
<ToolbarItem id = "Collapse" <ToolbarItem id = "Collapse"
icon = "Icons.16x16.Collection" icon = "Icons.16x16.Collection"
tooltip = "${res:MainWindow.Windows.SearchResultPanel.CollapseAll.ToolTip}" tooltip = "${res:MainWindow.Windows.SearchResultPanel.CollapseAll.ToolTip}"
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.ClassBrowserCollapseAll"/> class = "ICSharpCode.SharpDevelop.Dom.ClassBrowser.ClassBrowserCollapseAll"/>-->
</Path> </Path>
<Path name = "/SharpDevelop/Pads/ClassBrowser/Searchbar"> <Path name = "/SharpDevelop/Pads/ClassBrowser/Searchbar">
@ -988,6 +988,13 @@
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.ClassBrowserCancelSearch"/> class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.ClassBrowserCancelSearch"/>
</Path> </Path>
<Path name = "/SharpDevelop/Pads/ClassBrowser/AssemblyContextMenu">
<MenuItem id = "RemoveAssembly"
label = "Remove"
icon = "Icons.16x16.DeleteIcon"
class = "ICSharpCode.SharpDevelop.Dom.ClassBrowser.RemoveAssemblyCommand"/>
</Path>
<!-- end ClassBrowser --> <!-- end ClassBrowser -->
<!-- toolbars --> <!-- toolbars -->

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -84,6 +84,7 @@
</Compile> </Compile>
<Compile Include="Designer\IDesignerTypeResolutionService.cs" /> <Compile Include="Designer\IDesignerTypeResolutionService.cs" />
<Compile Include="Designer\TypeResolutionService.cs" /> <Compile Include="Designer\TypeResolutionService.cs" />
<Compile Include="Dom\ClassBrowser\AssemblyLoadErrorTreeNode.cs" />
<Compile Include="Dom\ClassBrowser\AssemblyTreeNode.cs" /> <Compile Include="Dom\ClassBrowser\AssemblyTreeNode.cs" />
<Compile Include="Dom\ClassBrowser\ClassBrowserTreeView.cs" /> <Compile Include="Dom\ClassBrowser\ClassBrowserTreeView.cs" />
<Compile Include="Dom\ClassBrowser\IClassBrowser.cs" /> <Compile Include="Dom\ClassBrowser\IClassBrowser.cs" />

1
src/Main/Base/Project/Src/Editor/Dialogs/RenameSymbolDialog.xaml.cs

@ -42,6 +42,7 @@ namespace ICSharpCode.SharpDevelop.Editor.Dialogs
// Set focus into TextBox // Set focus into TextBox
this.symbolNameTextBox.Focus(); this.symbolNameTextBox.Focus();
this.IsVisibleChanged += (sender, e) => this.symbolNameTextBox.SelectAll();
} }
public string OldSymbolName public string OldSymbolName

46
src/Main/Base/Project/Src/Gui/Pads/DefinitionViewPad.cs

@ -6,7 +6,7 @@ using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using ICSharpCode.AvalonEdit; using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core; using ICSharpCode.Core;
@ -24,14 +24,13 @@ namespace ICSharpCode.SharpDevelop.Gui
public class DefinitionViewPad : AbstractPadContent public class DefinitionViewPad : AbstractPadContent
{ {
AvalonEdit.TextEditor ctl; AvalonEdit.TextEditor ctl;
DispatcherTimer timer;
/// <summary> /// <summary>
/// The control representing the pad /// The control representing the pad
/// </summary> /// </summary>
public override object Control { public override object Control {
get { get { return ctl; }
return ctl;
}
} }
/// <summary> /// <summary>
@ -42,8 +41,11 @@ namespace ICSharpCode.SharpDevelop.Gui
ctl = Editor.AvalonEditTextEditorAdapter.CreateAvalonEditInstance(); ctl = Editor.AvalonEditTextEditorAdapter.CreateAvalonEditInstance();
ctl.IsReadOnly = true; ctl.IsReadOnly = true;
ctl.MouseDoubleClick += OnDoubleClick; ctl.MouseDoubleClick += OnDoubleClick;
throw new NotImplementedException(); SD.ParserService.ParseInformationUpdated += OnParserUpdateStep;
//ParserService.ParserUpdateStepFinished += OnParserUpdateStep; SD.ParserService.LoadSolutionProjectsThread.Finished += LoadThreadFinished;
timer = new DispatcherTimer(DispatcherPriority.Background) { Interval = TimeSpan.FromSeconds(2) };
timer.Tick += delegate { UpdateTick(null); };
timer.IsEnabled = !SD.ParserService.LoadSolutionProjectsThread.IsRunning;
ctl.IsVisibleChanged += delegate { UpdateTick(null); }; ctl.IsVisibleChanged += delegate { UpdateTick(null); };
} }
@ -52,47 +54,55 @@ namespace ICSharpCode.SharpDevelop.Gui
/// </summary> /// </summary>
public override void Dispose() public override void Dispose()
{ {
//ParserService.ParserUpdateStepFinished -= OnParserUpdateStep; SD.ParserService.ParseInformationUpdated -= OnParserUpdateStep;
SD.ParserService.LoadSolutionProjectsThread.Finished -= LoadThreadFinished;
ctl.Document = null; ctl.Document = null;
base.Dispose(); base.Dispose();
} }
void OnDoubleClick(object sender, EventArgs e) void OnDoubleClick(object sender, EventArgs e)
{ {
string fileName = currentFileName; FileName fileName = currentFileName;
if (fileName != null) { if (fileName != null) {
var caret = ctl.TextArea.Caret; var caret = ctl.TextArea.Caret;
FileService.JumpToFilePosition(fileName, caret.Line, caret.Column); SD.FileService.JumpToFilePosition(fileName, caret.Line, caret.Column);
// refresh DefinitionView to show the definition of the expression that was double-clicked // refresh DefinitionView to show the definition of the expression that was double-clicked
UpdateTick(null); UpdateTick(null);
} }
} }
void OnParserUpdateStep(object sender, ParserUpdateStepEventArgs e) void LoadThreadFinished(object sender, EventArgs e)
{
timer.IsEnabled = true;
UpdateTick(null);
}
void OnParserUpdateStep(object sender, ParseInformationEventArgs e)
{ {
UpdateTick(e); UpdateTick(e);
} }
async void UpdateTick(ParserUpdateStepEventArgs e) async void UpdateTick(ParseInformationEventArgs e)
{ {
timer.IsEnabled = ctl.IsVisible;
if (!ctl.IsVisible) return; if (!ctl.IsVisible) return;
LoggingService.Debug("DefinitionViewPad.Update"); LoggingService.Debug("DefinitionViewPad.Update");
ResolveResult res = await ResolveAtCaretAsync(e); ResolveResult res = await ResolveAtCaretAsync(e);
if (res == null) return; if (res == null) return;
var pos = res.GetDefinitionRegion(); var pos = res.GetDefinitionRegion();
if (pos.IsEmpty) return; if (pos.IsEmpty) return; // TODO : try to decompile?
OpenFile(pos); OpenFile(pos);
} }
Task<ResolveResult> ResolveAtCaretAsync(ParserUpdateStepEventArgs e) Task<ResolveResult> ResolveAtCaretAsync(ParseInformationEventArgs e)
{ {
IWorkbenchWindow window = SD.Workbench.ActiveWorkbenchWindow; IWorkbenchWindow window = SD.Workbench.ActiveWorkbenchWindow;
if (window == null) if (window == null)
return Task.FromResult<ResolveResult>(null); return Task.FromResult<ResolveResult>(null);
IViewContent viewContent = window.ActiveViewContent; IViewContent viewContent = window.ActiveViewContent;
if (viewContent == null) if (viewContent == null)
return Task.FromResult<ResolveResult>(null); return Task.FromResult<ResolveResult>(null);
ITextEditor editor = viewContent.GetService<ITextEditor>(); ITextEditor editor = viewContent.GetService<ITextEditor>();
if (editor == null) if (editor == null)
@ -107,14 +117,14 @@ namespace ICSharpCode.SharpDevelop.Gui
} }
DomRegion oldPosition; DomRegion oldPosition;
string currentFileName; FileName currentFileName;
void OpenFile(DomRegion pos) void OpenFile(DomRegion pos)
{ {
if (pos.Equals(oldPosition)) return; if (pos.Equals(oldPosition)) return;
oldPosition = pos; oldPosition = pos;
if (pos.FileName != currentFileName) if (pos.FileName != currentFileName)
LoadFile(pos.FileName); LoadFile(new FileName(pos.FileName));
ctl.TextArea.Caret.Location = pos.Begin; ctl.TextArea.Caret.Location = pos.Begin;
Rect r = ctl.TextArea.Caret.CalculateCaretRectangle(); Rect r = ctl.TextArea.Caret.CalculateCaretRectangle();
if (!r.IsEmpty) { if (!r.IsEmpty) {
@ -126,7 +136,7 @@ namespace ICSharpCode.SharpDevelop.Gui
/// Loads the file from the corresponding text editor window if it is /// Loads the file from the corresponding text editor window if it is
/// open otherwise the file is loaded from the file system. /// open otherwise the file is loaded from the file system.
/// </summary> /// </summary>
void LoadFile(string fileName) void LoadFile(FileName fileName)
{ {
// Load the text into the definition view's text editor. // Load the text into the definition view's text editor.
ctl.Document = new TextDocument(SD.FileService.GetFileContent(fileName)); ctl.Document = new TextDocument(SD.FileService.GetFileContent(fileName));

6
src/Main/SharpDevelop/Dom/AssemblyModel.cs

@ -50,6 +50,12 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
} }
public IEntityModelContext Context {
get {
return context;
}
}
public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile)
{ {
IList<IUnresolvedTypeDefinition> old = EmptyList<IUnresolvedTypeDefinition>.Instance; IList<IUnresolvedTypeDefinition> old = EmptyList<IUnresolvedTypeDefinition>.Instance;

229
src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs

@ -2,17 +2,78 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Windows.Controls; using System.Windows.Controls;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation; using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Workbench; using ICSharpCode.SharpDevelop.Workbench;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{ {
public class PersistedWorkspace
{
public PersistedWorkspace()
{
AssemblyFiles = new List<string>();
}
public string Name { get; set; }
public List<String> AssemblyFiles { get; set; }
public bool IsActive { get; set; }
}
class UnresolvedAssemblyEntityModelContext : IEntityModelContext
{
string assemblyName;
string location;
public UnresolvedAssemblyEntityModelContext(string assemblyName, string location)
{
this.assemblyName = assemblyName;
this.location = location;
}
public ICompilation GetCompilation()
{
return null;
}
public bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2)
{
return false;
}
public IProject Project {
get {
return null;
}
}
public string AssemblyName {
get {
return assemblyName;
}
}
public string Location {
get {
return location;
}
}
public bool IsValid {
get { return false; }
}
}
class ClassBrowserPad : AbstractPadContent, IClassBrowser class ClassBrowserPad : AbstractPadContent, IClassBrowser
{ {
#region IClassBrowser implementation #region IClassBrowser implementation
@ -25,13 +86,19 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
get { return treeView.AssemblyList; } get { return treeView.AssemblyList; }
set { treeView.AssemblyList = value; } set { treeView.AssemblyList = value; }
} }
#endregion #endregion
const string PersistedWorkspaceSetting = "ClassBrowser.Workspaces";
const string DefaultWorkspaceName = "<default>";
IProjectService projectService; IProjectService projectService;
ClassBrowserTreeView treeView; ClassBrowserTreeView treeView;
DockPanel panel; DockPanel panel;
ToolBar toolBar; ToolBar toolBar;
List<PersistedWorkspace> persistedWorkspaces;
PersistedWorkspace activeWorkspace;
public ClassBrowserPad() public ClassBrowserPad()
: this(SD.GetRequiredService<IProjectService>()) : this(SD.GetRequiredService<IProjectService>())
@ -53,6 +120,9 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
//treeView.ContextMenu = CreateContextMenu("/SharpDevelop/Pads/UnitTestsPad/ContextMenu"); //treeView.ContextMenu = CreateContextMenu("/SharpDevelop/Pads/UnitTestsPad/ContextMenu");
projectService.CurrentSolutionChanged += ProjectServiceCurrentSolutionChanged; projectService.CurrentSolutionChanged += ProjectServiceCurrentSolutionChanged;
ProjectServiceCurrentSolutionChanged(null, null); ProjectServiceCurrentSolutionChanged(null, null);
// Load workspaces from configuration
LoadWorkspaces();
} }
public override void Dispose() public override void Dispose()
@ -77,6 +147,26 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
treeView.SpecialNodes.Add(new SolutionTreeNode(projectService.CurrentSolution)); treeView.SpecialNodes.Add(new SolutionTreeNode(projectService.CurrentSolution));
} }
void AssemblyListCollectionChanged(IReadOnlyCollection<IAssemblyModel> removedItems, IReadOnlyCollection<IAssemblyModel> addedItems)
{
foreach (var assembly in addedItems) {
// Add this assembly to current workspace
if (activeWorkspace != null) {
activeWorkspace.AssemblyFiles.Add(assembly.Context.Location);
}
}
foreach (var assembly in removedItems) {
// Add this assembly to current workspace
if (activeWorkspace != null) {
activeWorkspace.AssemblyFiles.Remove(assembly.Context.Location);
}
}
// Update workspace list in configuration
SaveWorkspaces();
}
/// <summary> /// <summary>
/// Virtual method so we can override this method and return /// Virtual method so we can override this method and return
/// a dummy ToolBar when testing. /// a dummy ToolBar when testing.
@ -96,5 +186,142 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
Debug.Assert(treeView != null); Debug.Assert(treeView != null);
return MenuService.CreateContextMenu(treeView, name); return MenuService.CreateContextMenu(treeView, name);
} }
/// <summary>
/// Loads persisted workspaces from configuration.
/// </summary>
void LoadWorkspaces()
{
persistedWorkspaces = SD.PropertyService.GetList<PersistedWorkspace>(PersistedWorkspaceSetting).ToList();
if (!persistedWorkspaces.Any())
{
// Add at least default workspace
persistedWorkspaces = new List<PersistedWorkspace>();
persistedWorkspaces.Add(new PersistedWorkspace()
{
Name = DefaultWorkspaceName
});
}
// Load all assemblies (for now always from default workspace)
PersistedWorkspace defaultWorkspace = persistedWorkspaces.FirstOrDefault(w => w.Name == DefaultWorkspaceName);
ActivateWorkspace(defaultWorkspace);
}
/// <summary>
/// Stores currently saved workspaces in configuration.
/// </summary>
void SaveWorkspaces()
{
SD.PropertyService.SetList<PersistedWorkspace>(PersistedWorkspaceSetting, persistedWorkspaces);
}
public static IAssemblyModel CreateAssemblyModelFromFile(string fileName)
{
try {
var loader = new CecilLoader();
loader.IncludeInternalMembers = true;
loader.LazyLoad = true;
var assembly = loader.LoadAssemblyFile(fileName);
IEntityModelContext context = new AssemblyEntityModelContext(assembly);
IAssemblyModel model = SD.GetRequiredService<IModelFactory>().CreateAssemblyModel(context);
if (model is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)model).Update(EmptyList<IUnresolvedTypeDefinition>.Instance, assembly.TopLevelTypeDefinitions.ToList());
((IUpdateableAssemblyModel) model).AssemblyName = assembly.AssemblyName;
}
return model;
} catch (BadImageFormatException) {
SD.MessageService.ShowWarningFormatted("{0} is not a valid .NET assembly.", Path.GetFileName(fileName));
} catch (FileNotFoundException) {
SD.MessageService.ShowWarningFormatted("{0} is not accessible or doesn't exist anymore.", fileName);
}
return null;
}
static IAssemblyModel CreateAssemblyModelOrThrowException(string fileName)
{
var loader = new CecilLoader();
loader.IncludeInternalMembers = true;
loader.LazyLoad = true;
var assembly = loader.LoadAssemblyFile(fileName);
IEntityModelContext context = new AssemblyEntityModelContext(assembly);
IAssemblyModel model = SD.GetRequiredService<IModelFactory>().CreateAssemblyModel(context);
if (model is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)model).Update(EmptyList<IUnresolvedTypeDefinition>.Instance, assembly.TopLevelTypeDefinitions.ToList());
((IUpdateableAssemblyModel) model).AssemblyName = assembly.AssemblyName;
}
return model;
}
static IAssemblyModel SafelyCreateAssemblyModelFromFile(string fileName)
{
try {
return CreateAssemblyModelOrThrowException(fileName);
} catch (Exception) {
// Special AssemblyModel for unresolved file references
IEntityModelContext unresolvedContext = new UnresolvedAssemblyEntityModelContext(Path.GetFileName(fileName), fileName);
IAssemblyModel unresolvedModel = SD.GetRequiredService<IModelFactory>().CreateAssemblyModel(unresolvedContext);
if (unresolvedModel is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel) unresolvedModel).AssemblyName = unresolvedContext.AssemblyName;
}
return unresolvedModel;
}
}
void AppendAssemblyFileToList(string assemblyFile)
{
IAssemblyModel assemblyModel = SafelyCreateAssemblyModelFromFile(assemblyFile);
if (assemblyModel != null) {
AssemblyList.Assemblies.Add(assemblyModel);
}
}
/// <summary>
/// Activates the specified workspace.
/// </summary>
void ActivateWorkspace(PersistedWorkspace workspace)
{
// Update the activation flags in workspace list
foreach (var workspaceElement in persistedWorkspaces) {
workspaceElement.IsActive = (workspaceElement == workspace);
}
UpdateActiveWorkspace();
}
/// <summary>
/// Updates active workspace and AssemblyList according to <see cref="PersistedWorkspace.IsActive"/> flags.
/// </summary>
void UpdateActiveWorkspace()
{
if ((AssemblyList != null) && (activeWorkspace != null)) {
// Temporarily detach from event handler
AssemblyList.Assemblies.CollectionChanged -= AssemblyListCollectionChanged;
}
activeWorkspace = persistedWorkspaces.FirstOrDefault(w => w.IsActive);
if (activeWorkspace == null) {
// If no workspace is active, activate default
var defaultWorkspace = persistedWorkspaces.FirstOrDefault(w => w.Name == DefaultWorkspaceName);
activeWorkspace = defaultWorkspace;
defaultWorkspace.IsActive = true;
}
AssemblyList.Assemblies.Clear();
if (activeWorkspace != null) {
foreach (string assemblyFile in activeWorkspace.AssemblyFiles) {
AppendAssemblyFileToList(assemblyFile);
}
}
// Attach to event handler, again.
if (AssemblyList != null) {
AssemblyList.Assemblies.CollectionChanged += AssemblyListCollectionChanged;
}
}
} }
} }

4
src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserTreeNodesFactory.cs

@ -21,6 +21,8 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
return typeof(ITypeDefinitionModel); return typeof(ITypeDefinitionModel);
if (model is IMemberModel) if (model is IMemberModel)
return typeof(IMemberModel); return typeof(IMemberModel);
if (model is IAssemblyModel)
return typeof(IAssemblyModel);
return null; return null;
} }
@ -36,6 +38,8 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
return new TypeDefinitionTreeNode((ITypeDefinitionModel)model); return new TypeDefinitionTreeNode((ITypeDefinitionModel)model);
if (model is IMemberModel) if (model is IMemberModel)
return new MemberTreeNode((IMemberModel)model); return new MemberTreeNode((IMemberModel)model);
if (model is IAssemblyModel)
return new AssemblyTreeNode((IAssemblyModel) model);
return null; return null;
} }
} }

75
src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs

@ -0,0 +1,75 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using System.Linq;
using Microsoft.Win32;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
/// <summary>
/// OpenAssemblyFromFileCommand.
/// </summary>
class OpenAssemblyFromFileCommand : SimpleCommand
{
public override void Execute(object parameter)
{
var classBrowser = SD.GetService<IClassBrowser>();
if (classBrowser != null) {
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Assembly files (*.exe, *.dll)|*.exe;*.dll";
openFileDialog.CheckFileExists = true;
openFileDialog.CheckPathExists = true;
if (openFileDialog.ShowDialog() ?? false)
{
IAssemblyModel assemblyModel = ClassBrowserPad.CreateAssemblyModelFromFile(openFileDialog.FileName);
if (assemblyModel != null)
classBrowser.AssemblyList.Assemblies.Add(assemblyModel);
}
}
}
}
/// <summary>
/// OpenAssemblyFromGACCommand.
/// </summary>
class OpenAssemblyFromGACCommand : SimpleCommand
{
public override void Execute(object parameter)
{
var classBrowser = SD.GetService<IClassBrowser>();
if (classBrowser != null) {
OpenFromGacDialog gacDialog = new OpenFromGacDialog();
if (gacDialog.ShowDialog() ?? false)
{
foreach (string assemblyFile in gacDialog.SelectedFileNames) {
IAssemblyModel assemblyModel = ClassBrowserPad.CreateAssemblyModelFromFile(assemblyFile);
if (assemblyModel != null)
classBrowser.AssemblyList.Assemblies.Add(assemblyModel);
}
}
}
}
}
/// <summary>
/// RemoveAssemblyCommand.
/// </summary>
class RemoveAssemblyCommand : SimpleCommand
{
public override bool CanExecute(object parameter)
{
return parameter is AssemblyModel;
}
public override void Execute(object parameter)
{
var classBrowser = SD.GetService<IClassBrowser>();
if (classBrowser != null) {
IAssemblyModel assemblyModel = (IAssemblyModel) parameter;
classBrowser.AssemblyList.Assemblies.Remove(assemblyModel);
}
}
}
}

29
src/Main/SharpDevelop/Dom/ClassBrowser/OpenAssemblyCommand.cs

@ -1,29 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
/// <summary>
/// Description of OpenAssemblyFromFileCommand.
/// </summary>
class OpenAssemblyFromFileCommand : SimpleCommand
{
public override void Execute(object parameter)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Description of OpenAssemblyFromGACCommand.
/// </summary>
class OpenAssemblyFromGACCommand : SimpleCommand
{
public override void Execute(object parameter)
{
throw new NotImplementedException();
}
}
}

46
src/Main/SharpDevelop/Dom/ClassBrowser/OpenFromGacDialog.xaml

@ -0,0 +1,46 @@
<Window
x:Class="ICSharpCode.SharpDevelop.Dom.ClassBrowser.OpenFromGacDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="http://icsharpcode.net/sharpdevelop/core"
Title="Open From GAC"
Style = "{x:Static core:GlobalStyles.DialogWindowStyle}"
WindowStartupLocation="CenterOwner"
ResizeMode="CanResizeWithGrip"
MinWidth="200"
MinHeight="150"
Height="350"
Width="750"
FocusManager.FocusedElement="{Binding ElementName=filterTextBox}">
<Grid
Margin="12,8">
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition
Height="1*" />
<RowDefinition
Height="Auto" />
</Grid.RowDefinitions>
<DockPanel>
<Label DockPanel.Dock="Left" Target="{Binding ElementName=filterTextBox}">_Search:</Label>
<TextBox Name="filterTextBox" TextChanged="FilterTextBox_TextChanged" />
</DockPanel>
<ListView Name="listView" Grid.Row="1" Margin="0, 8" core:SortableGridViewColumn.SortMode="Automatic" SelectionChanged="ListView_SelectionChanged">
<ListView.View>
<GridView>
<core:SortableGridViewColumn x:Name="nameColumn" Width="300" Header="Reference Name" DisplayMemberBinding="{Binding ShortName}" />
<core:SortableGridViewColumn Width="75" Header="Version" DisplayMemberBinding="{Binding Version}" />
<core:SortableGridViewColumn Width="65" Header="Culture" DisplayMemberBinding="{Binding Culture}" />
<core:SortableGridViewColumn Width="115" Header="Public Key Token" DisplayMemberBinding="{Binding PublicKeyToken}" />
<core:SortableGridViewColumn Width="1000" Header="Location" DisplayMemberBinding="{Binding FileName}" />
</GridView>
</ListView.View>
</ListView>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button IsDefault="True" Margin="2,0" Height="23" MinWidth="75" IsEnabled="False" Name="okButton" Click="OKButton_Click">Open</Button>
<Button IsCancel="True" Margin="2,0" Height="23" MinWidth="75">Cancel</Button>
</StackPanel>
<ProgressBar Grid.Row="1" Height="10" HorizontalAlignment="Stretch" Name="gacReadingProgressBar" VerticalAlignment="Bottom" Visibility="Hidden" />
</Grid>
</Window>

188
src/Main/SharpDevelop/Dom/ClassBrowser/OpenFromGacDialog.xaml.cs

@ -0,0 +1,188 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Parser;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
/// <summary>
/// Interaction logic for OpenFromGacDialog.xaml
/// </summary>
public partial class OpenFromGacDialog : Window
{
ObservableCollection<GacEntry> gacEntries = new ObservableCollection<GacEntry>();
ObservableCollection<GacEntry> filteredEntries = new ObservableCollection<GacEntry>();
Predicate<GacEntry> filterMethod = _ => true;
volatile bool cancelFetchThread;
public OpenFromGacDialog()
{
InitializeComponent();
FormLocationHelper.ApplyWindow(this, "ICSharpCode.SharpDevelop.Dom.OpenFromGacDialog.Bounds", true);
listView.ItemsSource = filteredEntries;
SortableGridViewColumn.SetCurrentSortColumn(listView, nameColumn);
SortableGridViewColumn.SetSortDirection(listView, ColumnSortDirection.Ascending);
new Thread(new ThreadStart(FetchGacContents)).Start();
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
cancelFetchThread = true;
}
#region Fetch Gac Contents
sealed class GacEntry
{
readonly DomAssemblyName r;
readonly string fileName;
string formattedVersion;
public GacEntry(DomAssemblyName r, string fileName)
{
this.r = r;
this.fileName = fileName;
}
public string FullName {
get { return r.FullName; }
}
public string ShortName {
get { return r.ShortName; }
}
public string FileName {
get { return fileName; }
}
public Version Version {
get { return r.Version; }
}
public string FormattedVersion {
get {
if (formattedVersion == null)
formattedVersion = Version.ToString();
return formattedVersion;
}
}
public string Culture {
get { return r.Culture; }
}
public string PublicKeyToken {
get {
StringBuilder s = new StringBuilder();
foreach (byte b in r.PublicKeyToken)
s.Append(b.ToString("x2"));
return s.ToString();
}
}
public override string ToString()
{
return r.FullName;
}
}
void FetchGacContents()
{
IGlobalAssemblyCacheService gacService = SD.GetService<IGlobalAssemblyCacheService>();
HashSet<string> fullNames = new HashSet<string>();
UpdateProgressBar(pg => { pg.Visibility = System.Windows.Visibility.Visible; pg.IsIndeterminate = true; });
var list = gacService.Assemblies.TakeWhile(_ => !cancelFetchThread).ToList();
UpdateProgressBar(pg => { pg.IsIndeterminate = false; pg.Maximum = list.Count; });
foreach (var r in list) {
if (cancelFetchThread)
break;
if (fullNames.Add(r.FullName)) { // filter duplicates
var file = gacService.FindAssemblyInNetGac(r);
if (file != null) {
var entry = new GacEntry(r, file);
UpdateProgressBar(pg => { pg.Value = pg.Value + 1; AddNewEntry(entry); });
}
}
}
UpdateProgressBar(pg => { pg.Visibility = System.Windows.Visibility.Hidden; });
}
void UpdateProgressBar(Action<ProgressBar> updateAction)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => updateAction(gacReadingProgressBar)));
}
void AddNewEntry(GacEntry entry)
{
gacEntries.Add(entry);
if (filterMethod(entry))
filteredEntries.Add(entry);
}
#endregion
void FilterTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
string filterString = filterTextBox.Text.Trim();
if (filterString.Length == 0)
filterMethod = _ => true;
else {
var elements = filterString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
filterMethod = entry => elements.All(el => Contains(entry.FullName, el) || Contains(entry.FormattedVersion, el));
}
filteredEntries.Clear();
filteredEntries.AddRange(gacEntries.Where(entry => filterMethod(entry)));
}
static bool Contains(string s, string subString)
{
return s.IndexOf(subString, StringComparison.OrdinalIgnoreCase) >= 0;
}
void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
okButton.IsEnabled = listView.SelectedItems.Count > 0;
}
void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
Close();
}
public string[] SelectedFileNames {
get {
return listView.SelectedItems.OfType<GacEntry>().Select(e => e.FileName).ToArray();
}
}
}
}

BIN
src/Main/SharpDevelop/Resources/BitmapResources.resources

Binary file not shown.

7
src/Main/SharpDevelop/SharpDevelop.csproj

@ -108,7 +108,11 @@
</Compile> </Compile>
<Compile Include="Dom\ClassBrowser\ClassBrowserPad.cs" /> <Compile Include="Dom\ClassBrowser\ClassBrowserPad.cs" />
<Compile Include="Dom\ClassBrowser\ClassBrowserTreeNodesFactory.cs" /> <Compile Include="Dom\ClassBrowser\ClassBrowserTreeNodesFactory.cs" />
<Compile Include="Dom\ClassBrowser\OpenAssemblyCommand.cs" /> <Compile Include="Dom\ClassBrowser\Commands.cs" />
<Compile Include="Dom\ClassBrowser\OpenFromGacDialog.xaml.cs">
<DependentUpon>OpenFromGacDialog.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Dom\ModelFactory.cs" /> <Compile Include="Dom\ModelFactory.cs" />
<Compile Include="Dom\MemberModel.cs" /> <Compile Include="Dom\MemberModel.cs" />
<Compile Include="Dom\NamespaceModel.cs" /> <Compile Include="Dom\NamespaceModel.cs" />
@ -331,6 +335,7 @@
<Folder Include="Workbench\DisplayBinding" /> <Folder Include="Workbench\DisplayBinding" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Include="Dom\ClassBrowser\OpenFromGacDialog.xaml" />
<Page Include="OptionPanels\LoadSaveOptions.xaml" /> <Page Include="OptionPanels\LoadSaveOptions.xaml" />
<Page Include="Startup\App.xaml" /> <Page Include="Startup\App.xaml" />
<Page Include="Workbench\WpfWorkbench.xaml" /> <Page Include="Workbench\WpfWorkbench.xaml" />

Loading…
Cancel
Save