Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorLluis Sanchez <llsan@microsoft.com>2019-03-20 01:31:47 +0300
committerLluis Sanchez <llsan@microsoft.com>2019-03-20 01:31:47 +0300
commit935f47982ef658566f1b1af36acdd5ca46cdb323 (patch)
treefeafb21d99ed8eda14ca390c2691cb87184daec9 /main
parent683355b7bbd702f60f27946ea97581302650461f (diff)
parent40d52a9e69683bf9da9aecaeb6e0a75464dd83cc (diff)
Merge remote-tracking branch 'origin/master' into new-service-model
Diffstat (limited to 'main')
-rw-r--r--main/Main.sln25
m---------main/external/Xamarin.PropertyEditing0
-rw-r--r--main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpSymbolHelper.fs9
-rw-r--r--main/src/addins/AspNet/Projects/AspNetAppProjectFlavor.cs8
-rw-r--r--main/src/addins/AspNet/Projects/WebSubtype.cs3
-rw-r--r--main/src/addins/AspNet/Templates/EmptyTypeScriptFile.xft.xml2
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs2
-rw-r--r--main/src/addins/MacPlatform/MacInterop/Keychain.cs688
-rw-r--r--main/src/addins/MacPlatform/MacPlatform.cs43
-rw-r--r--main/src/addins/MacPlatform/MacProxyCredentialProvider.cs7
-rw-r--r--main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs12
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.Visualizer/TextVisualizer.cs2
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebugCommands.cs12
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs108
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Projects/ProjectFileDescriptor.cs8
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs5
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj26
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs77
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs16
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs164
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyDescriptorEventInfo.cs66
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DescriptorPropertyInfo.cs155
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs71
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/EnumDescriptorPropertyInfo.cs111
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs66
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FlagDescriptorPropertyInfo.cs91
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/StringStandardValuesPropertyInfo.cs57
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs80
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs235
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyProviderTypeInfo.cs47
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs169
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPadVisitor.cs2
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs127
-rw-r--r--main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Templating/DotNetCoreProjectTemplateStringTagProvider.cs12
-rw-r--r--main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTests.cs4
-rw-r--r--main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs4
-rw-r--r--main/src/addins/MonoDevelop.DotNetCore/Properties/MonoDevelop.DotNetCore.addin.xml42
-rw-r--r--main/src/addins/MonoDevelop.GtkCore/MonoDevelop.GtkCore.GuiBuilder/GuiBuilderService.cs2
-rw-r--r--main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj1
-rw-r--r--main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/InstallPackageWithAvailableItemNameTests.cs74
-rw-r--r--main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackageReferenceNuGetProjectTests.cs42
-rw-r--r--main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/PackageReferenceNuGetProject.cs26
-rw-r--r--main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/NuGetPackageMetadata.cs2
-rw-r--r--main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs5
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj1
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitCredentials.cs52
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitVersionControl.cs15
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/IGitCredentialsProvider.cs57
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs7
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/MergeView.cs108
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs51
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlSystem.cs46
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs30
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngine.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs12
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs8
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs36
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs49
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs15
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs16
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ViewCommands.cs1
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/ProgressDialog.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ProgressMonitoring/MessageDialogProgressMonitor.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs1
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs36
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageCommands.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj5
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs87
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs69
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs43
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs3
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Services.cs3
-rw-r--r--main/tests/Ide.Tests/MonoDevelop.Ide.Tests.csproj1
-rw-r--r--main/tests/Ide.Tests/MonoDevelop.Ide/BaseCredentialsProviderTests.cs (renamed from main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core/BaseCredentialsProviderTests.cs)8
-rw-r--r--main/tests/MacPlatform.Tests/CredentialsProviderTests.cs24
-rw-r--r--main/tests/MacPlatform.Tests/KeychainTests.cs259
-rw-r--r--main/tests/MacPlatform.Tests/MacPlatform.Tests.csproj5
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj2
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs78
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SharedAssetsProjectTests.cs32
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SolutionTests.cs57
-rw-r--r--main/tests/WindowsPlatform.Tests/CredentialsProviderTests.cs2
-rw-r--r--main/tests/WindowsPlatform.Tests/WindowsPlatform.Tests.csproj13
-rw-r--r--main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.csproj36
-rw-r--r--main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.sln19
-rw-r--r--main/tests/test-projects/SharedProjectMissingImport/Shared.shproj6
-rw-r--r--main/tests/test-projects/SharedProjectTypeGuidMismatch/Library.csproj35
-rw-r--r--main/tests/test-projects/SharedProjectTypeGuidMismatch/SharedProjectTypeGuidMismatch.sln15
93 files changed, 3004 insertions, 1080 deletions
diff --git a/main/Main.sln b/main/Main.sln
index b6f11f9a2f..350af96707 100644
--- a/main/Main.sln
+++ b/main/Main.sln
@@ -261,15 +261,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FSharpBinding", "FSharpBind
external\fsharpbinding\build.fsx = external\fsharpbinding\build.fsx
EndProjectSection
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharp", "external\fsharpbinding\MonoDevelop.FSharpBinding\MonoDevelop.FSharp.fsproj", "{4C10F8F9-3816-4647-BA6E-85F5DE39883A}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharp", "external\fsharpbinding\MonoDevelop.FSharpBinding\MonoDevelop.FSharp.fsproj", "{4C10F8F9-3816-4647-BA6E-85F5DE39883A}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharp.Shared", "external\fsharpbinding\MonoDevelop.FSharp.Shared\MonoDevelop.FSharp.Shared.fsproj", "{AF5FEAD5-B50E-4F07-A274-32F23D5C504D}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharp.Shared", "external\fsharpbinding\MonoDevelop.FSharp.Shared\MonoDevelop.FSharp.Shared.fsproj", "{AF5FEAD5-B50E-4F07-A274-32F23D5C504D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.FSharp.Gui", "external\fsharpbinding\MonoDevelop.FSharp.Gui\MonoDevelop.FSharp.Gui.csproj", "{FD0D1033-9145-48E5-8ED8-E2365252878C}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharpInteractive.Service", "external\fsharpbinding\MonoDevelop.FSharpi.Service\MonoDevelop.FSharpInteractive.Service.fsproj", "{20D6EC2C-B62E-49D1-B685-90D8967A5B5D}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharpInteractive.Service", "external\fsharpbinding\MonoDevelop.FSharpi.Service\MonoDevelop.FSharpInteractive.Service.fsproj", "{20D6EC2C-B62E-49D1-B685-90D8967A5B5D}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharp.Tests", "external\fsharpbinding\MonoDevelop.FSharp.Tests\MonoDevelop.FSharp.Tests.fsproj", "{A1A45375-7FB8-4F2A-850F-FBCC67739927}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MonoDevelop.FSharp.Tests", "external\fsharpbinding\MonoDevelop.FSharp.Tests\MonoDevelop.FSharp.Tests.fsproj", "{A1A45375-7FB8-4F2A-850F-FBCC67739927}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Mono.TextEditor.Shared", "src\core\Mono.TextEditor.Shared\Mono.TextEditor.Shared.shproj", "{FBAAD910-F29B-4AC5-9FC0-27F6EB36C495}"
EndProject
@@ -339,6 +339,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.AspNetCore.Test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionTools", "src\tools\ExtensionTools\ExtensionTools.csproj", "{E33F7901-AA45-4C25-9868-DBB6CC8DC40C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.PropertyEditing", "external\Xamarin.PropertyEditing\Xamarin.PropertyEditing\Xamarin.PropertyEditing.csproj", "{A0B6FE73-D046-4E1C-BA9D-F20683889C5A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Xamarin.PropertyEditing", "Xamarin.PropertyEditing", "{48087117-8851-402C-B8EA-38681EEF48ED}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.PropertyEditing.Mac", "external\Xamarin.PropertyEditing\Xamarin.PropertyEditing.Mac\Xamarin.PropertyEditing.Mac.csproj", "{E8F4F0EB-C2B1-4116-8459-E076E0E0E485}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\core\Mono.TextEditor.Shared\Mono.TextEditor.Shared.projitems*{f8f92aa4-a376-4679-a9d4-60e7b7fbf477}*SharedItemsImports = 4
@@ -2133,6 +2139,14 @@ Global
{E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Debug|x86.Build.0 = Debug|Any CPU
{E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Release|x86.ActiveCfg = Release|Any CPU
{E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Release|x86.Build.0 = Release|Any CPU
+ {A0B6FE73-D046-4E1C-BA9D-F20683889C5A}.DebugMac|Any CPU.ActiveCfg = Debug|Any CPU
+ {A0B6FE73-D046-4E1C-BA9D-F20683889C5A}.DebugMac|Any CPU.Build.0 = Debug|Any CPU
+ {A0B6FE73-D046-4E1C-BA9D-F20683889C5A}.ReleaseMac|Any CPU.ActiveCfg = Release|Any CPU
+ {A0B6FE73-D046-4E1C-BA9D-F20683889C5A}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU
+ {E8F4F0EB-C2B1-4116-8459-E076E0E0E485}.DebugMac|Any CPU.ActiveCfg = Debug|Any CPU
+ {E8F4F0EB-C2B1-4116-8459-E076E0E0E485}.DebugMac|Any CPU.Build.0 = Debug|Any CPU
+ {E8F4F0EB-C2B1-4116-8459-E076E0E0E485}.ReleaseMac|Any CPU.ActiveCfg = Release|Any CPU
+ {E8F4F0EB-C2B1-4116-8459-E076E0E0E485}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE;
@@ -2285,6 +2299,9 @@ Global
{82B9A5C5-5713-49B5-93D1-BE29B00FF35A} = {D0469BC0-3DF4-4CE9-A9E3-3268359BAC2E}
{44FFFDDA-156F-49F9-AE6A-BA640C198B33} = {1DEFDD53-2677-439D-906E-141ED2AEC19B}
{E33F7901-AA45-4C25-9868-DBB6CC8DC40C} = {5D3F7E65-E55B-45CA-A83B-D1E10040281E}
+ {A0B6FE73-D046-4E1C-BA9D-F20683889C5A} = {48087117-8851-402C-B8EA-38681EEF48ED}
+ {48087117-8851-402C-B8EA-38681EEF48ED} = {F12939F1-D55A-4CE9-9F33-8D959BFC7D6C}
+ {E8F4F0EB-C2B1-4116-8459-E076E0E0E485} = {48087117-8851-402C-B8EA-38681EEF48ED}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {856CF524-E2A7-4DB0-B80F-8F1B080A2E25}
diff --git a/main/external/Xamarin.PropertyEditing b/main/external/Xamarin.PropertyEditing
new file mode 160000
+Subproject 3309836f5d2677951e5bd9b7d507a5fe9cae33c
diff --git a/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpSymbolHelper.fs b/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpSymbolHelper.fs
index e3c2e5e4c5..df70a0a729 100644
--- a/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpSymbolHelper.fs
+++ b/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpSymbolHelper.fs
@@ -375,11 +375,16 @@ module Highlight =
|> Async.AwaitTask
|> Async.RunSynchronously
- let syntaxHighlight s =
- Runtime.RunInMainThread(fun() -> editor.Text <- s) |> Async.AwaitTask |> Async.RunSynchronously
+ let getHighlightedMarkup s =
+ editor.Text <- s
let data = editor.GetContent<ITextEditorDataProvider>().GetTextEditorData()
data.GetMarkup(0, s.Length, false, true, false, true)
+ let syntaxHighlight s =
+ Runtime.RunInMainThread (fun () -> getHighlightedMarkup s)
+ |> Async.AwaitTask
+ |> Async.RunSynchronously
+
let asUnderline = sprintf "_STARTUNDERLINE_%s_ENDUNDERLINE_" // we replace with real markup after highlighting
module SymbolTooltips =
diff --git a/main/src/addins/AspNet/Projects/AspNetAppProjectFlavor.cs b/main/src/addins/AspNet/Projects/AspNetAppProjectFlavor.cs
index 08133edf1d..17a81a259b 100644
--- a/main/src/addins/AspNet/Projects/AspNetAppProjectFlavor.cs
+++ b/main/src/addins/AspNet/Projects/AspNetAppProjectFlavor.cs
@@ -60,6 +60,7 @@ namespace MonoDevelop.AspNet.Projects
WebFormsRegistrationCache registrationCache;
WebFormsCodeBehindTypeNameCache codebehindTypeNameCache;
+ public const string TypeScriptCompile = "TypeScriptCompile";
#region properties
@@ -303,6 +304,8 @@ namespace MonoDevelop.AspNet.Projects
return WebSubtype.Stylus;
case "CSHTML":
return WebSubtype.Razor;
+ case "TS":
+ return WebSubtype.TypeScript;
default:
return WebSubtype.None;
}
@@ -546,11 +549,12 @@ namespace MonoDevelop.AspNet.Projects
protected override string OnGetDefaultBuildAction (string fileName)
{
-
- WebSubtype type = DetermineWebSubtype (fileName);
+ var type = DetermineWebSubtype (fileName);
switch (type) {
case WebSubtype.Code:
return BuildAction.Compile;
+ case WebSubtype.TypeScript:
+ return TypeScriptCompile;
case WebSubtype.None:
return base.OnGetDefaultBuildAction (fileName);
default:
diff --git a/main/src/addins/AspNet/Projects/WebSubtype.cs b/main/src/addins/AspNet/Projects/WebSubtype.cs
index 24bd85dbb4..766578ab20 100644
--- a/main/src/addins/AspNet/Projects/WebSubtype.cs
+++ b/main/src/addins/AspNet/Projects/WebSubtype.cs
@@ -53,7 +53,8 @@ namespace MonoDevelop.AspNet.Projects
Svg,
Sass,
Stylus,
- Razor
+ Razor,
+ TypeScript
}
}
diff --git a/main/src/addins/AspNet/Templates/EmptyTypeScriptFile.xft.xml b/main/src/addins/AspNet/Templates/EmptyTypeScriptFile.xft.xml
index ba60eb2595..30a6a4a012 100644
--- a/main/src/addins/AspNet/Templates/EmptyTypeScriptFile.xft.xml
+++ b/main/src/addins/AspNet/Templates/EmptyTypeScriptFile.xft.xml
@@ -14,6 +14,6 @@
</TemplateConfiguration>
<TemplateFiles>
- <File DefaultExtension=".ts" src="TypeScriptFileTemplate.ts" />
+ <File DefaultExtension=".ts" src="TypeScriptFileTemplate.ts" BuildAction="TypeScriptCompile" />
</TemplateFiles>
</Template>
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs
index 3ae26b0d8c..9feb21b991 100644
--- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs
@@ -145,6 +145,8 @@ namespace MonoDevelop.CSharp.Project
cryptoKeyFile: ParentConfiguration.SignAssembly ? ParentConfiguration.AssemblyKeyFile : null,
cryptoPublicKey: ImmutableArray<byte>.Empty,
platform: GetPlatform (),
+ publicSign: ParentConfiguration.PublicSign,
+ delaySign: ParentConfiguration.DelaySign,
generalDiagnosticOption: TreatWarningsAsErrors ? ReportDiagnostic.Error : ReportDiagnostic.Default,
warningLevel: WarningLevel,
specificDiagnosticOptions: GetSpecificDiagnosticOptions (),
diff --git a/main/src/addins/MacPlatform/MacInterop/Keychain.cs b/main/src/addins/MacPlatform/MacInterop/Keychain.cs
index 2196fe09df..64b76c6ff1 100644
--- a/main/src/addins/MacPlatform/MacInterop/Keychain.cs
+++ b/main/src/addins/MacPlatform/MacInterop/Keychain.cs
@@ -3,9 +3,11 @@
//
// Authors: Michael Hutchinson <mhutchinson@novell.com>
// Jeffrey Stedfast <jeff@xamarin.com>
+// Javier Suárez <jsuarez@microsoft.com>
//
// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
// Copyright (c) 2013 Xamarin Inc. (http://www.xamarin.com)
+// Copyright (c) 2019 Microsoft Corporation (http://www.microsoft.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -26,624 +28,232 @@
// THE SOFTWARE.
using System;
-using System.Text;
-using System.Runtime.InteropServices;
using Security;
+using Foundation;
namespace MonoDevelop.MacInterop
{
public static class Keychain
{
- const string CoreFoundationLib = ObjCRuntime.Constants.CoreFoundationLibrary;
- const string SecurityLib = ObjCRuntime.Constants.SecurityLibrary;
-
- internal static IntPtr CurrentKeychain = IntPtr.Zero;
-
- [DllImport (CoreFoundationLib, EntryPoint="CFRelease")]
- static extern void CFReleaseInternal (IntPtr cfRef);
-
- static void CFRelease (IntPtr cfRef)
+ public static void AddInternetPassword (Uri uri, string password)
{
- if (cfRef != IntPtr.Zero)
- CFReleaseInternal (cfRef);
- }
-
- #region Managing Keychains
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainCreate (byte[] pathName, uint passwordLength, byte[] password,
- bool promptUser, IntPtr initialAccess, out IntPtr keychain);
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainDelete (IntPtr keychain);
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainOpen (byte[] pathName, out IntPtr keychain);
+ // See if there is already a password there for this uri
+ var record = SecKeychainFindInternetPassword (uri, out SecRecord searchRecord);
- internal static IntPtr CreateKeychain (string path, string password)
- {
- var passwd = Encoding.UTF8.GetBytes (password);
+ if (record == null) {
+ record = uri.ToSecRecord (password: password);
- var status = SecKeychainCreate (path.ToNullTerminatedUtf8 (), (uint) passwd.Length, passwd, false, IntPtr.Zero, out IntPtr result);
- if (status != SecStatusCode.Success)
- throw new Exception (status.GetStatusDescription ());
+ SecStatusCode result = SecKeyChain.Add (record);
- return result;
- }
+ if (result != SecStatusCode.Success && result != SecStatusCode.DuplicateItem)
+ throw new Exception ("Could not add internet password to keychain: " + result.GetStatusDescription ());
- internal static bool TryDeleteKeychain (string path)
- {
- var result = SecKeychainOpen (path.ToNullTerminatedUtf8 (), out IntPtr ptr);
- try {
- if (result == SecStatusCode.Success) {
- DeleteKeychain (ptr);
- return true;
- }
- } catch {
- // If we call 'SecKeychainOpen' on a keychain path that does not exist,
- // we get a return value of 'success' and we also get a non-null handle.
- // As such there's no way for the test suite to safely check if a keychain
- // exists so it can delete a pre-existing one before exceuting. Work around
- // this by wrapping in a try/catch. The 'DeleteKeyChain (IntPtr)' method
- // will throw a 'key chain does not exist' error if there is no pre-existing
- // keychain
- } finally {
- CFRelease (ptr);
+ return;
}
- return false;
- }
- internal static void DeleteKeychain (IntPtr keychain)
- {
- var status = SecKeychainDelete (keychain);
- if (status != SecStatusCode.Success)
- throw new Exception (status.GetStatusDescription ());
- }
-
- #endregion
-
- #region Storing and Retrieving Passwords
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainAddInternetPassword (IntPtr keychain, uint serverNameLength, byte[] serverName, uint securityDomainLength,
- byte[] securityDomain, uint accountNameLength, byte[] accountName, uint pathLength,
- byte[] path, ushort port, SecProtocolType protocol, SecAuthenticationType authType,
- uint passwordLength, byte[] passwordData, ref IntPtr itemRef);
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainFindInternetPassword (IntPtr keychain, uint serverNameLength, byte[] serverName, uint securityDomainLength,
- byte[] securityDomain, uint accountNameLength, byte[] accountName, uint pathLength,
- byte[] path, ushort port, SecProtocolType protocol, SecAuthenticationType authType,
- out uint passwordLength, out IntPtr passwordData, ref IntPtr itemRef);
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainFindInternetPassword (IntPtr keychain, uint serverNameLength, byte[] serverName, uint securityDomainLength,
- byte[] securityDomain, uint accountNameLength, byte[] accountName, uint pathLength,
- byte[] path, ushort port, SecProtocolType protocol, SecAuthenticationType authType,
- IntPtr passwordLengthRef, IntPtr passwordDataRef, ref IntPtr itemRef);
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainAddGenericPassword (IntPtr keychain, uint serviceNameLength, byte[] serviceName,
- uint accountNameLength, byte[] accountName, uint passwordLength,
- byte[] passwordData, ref IntPtr itemRef);
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainFindGenericPassword (IntPtr keychain, uint serviceNameLength, byte[] serviceName,
- uint accountNameLength, byte[] accountName, out uint passwordLength,
- out IntPtr passwordData, ref IntPtr itemRef);
-
- #endregion
-
- #region Creating and Deleting Keychain Items
-
- [StructLayout (LayoutKind.Sequential)]
- struct SecKeychainAttributeList
- {
- public int Count;
- public IntPtr Attrs;
+ record.ValueData = NSData.FromString (password);
- public SecKeychainAttributeList (int count, IntPtr attrs)
- {
- Count = count;
- Attrs = attrs;
- }
+ // If there is, replace it with the new one
+ SecKeyChain.Update (searchRecord, record);
}
- [StructLayout (LayoutKind.Sequential)]
- struct SecKeychainAttribute
+ public static void AddInternetPassword (Uri uri, string username, string password)
{
- public SecItemAttr Tag;
- public uint Length;
- public IntPtr Data;
-
- public SecKeychainAttribute (SecItemAttr tag, uint length, IntPtr data)
- {
- Tag = tag;
- Length = length;
- Data = data;
- }
- }
+ // See if there is already a password there for this uri
+ var record = SecKeychainFindInternetPassword (uri, out SecRecord searchRecord);
- [DllImport (SecurityLib)]
- static extern unsafe SecStatusCode SecKeychainItemCreateFromContent (SecItemClass itemClass, SecKeychainAttributeList *attrList,
- uint passwordLength, byte[] password, IntPtr keychain,
- IntPtr initialAccess, IntPtr itemRef);
+ if (record == null) {
+ record = uri.ToSecRecord (username, password);
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainItemDelete (IntPtr itemRef);
+ SecStatusCode result = SecKeyChain.Add (record);
- #endregion
+ if (result != SecStatusCode.Success && result != SecStatusCode.DuplicateItem)
+ throw new Exception ("Could not add internet password to keychain: " + result.GetStatusDescription ());
- #region Managing Keychain Items
+ return;
+ }
- [StructLayout (LayoutKind.Sequential)]
- unsafe struct SecKeychainAttributeInfo
- {
- public uint Count;
- public int* Tag;
- public int* Format;
+ // If there is, replace it with the new one
+ var update = uri.ToSecRecord (username, password);
+ SecKeyChain.Update (record, update);
}
- [DllImport (SecurityLib)]
- static extern unsafe SecStatusCode SecKeychainItemFreeAttributesAndData (SecKeychainAttributeList* list, IntPtr data);
-
- [DllImport (SecurityLib)]
- static extern unsafe SecStatusCode SecKeychainItemCopyAttributesAndData (IntPtr itemRef, SecKeychainAttributeInfo* info, ref SecItemClass itemClass,
- SecKeychainAttributeList** attrList, IntPtr lengthRef, IntPtr outDataRef);
-
- [DllImport (SecurityLib)]
- static extern unsafe SecStatusCode SecKeychainItemModifyAttributesAndData (IntPtr itemRef, SecKeychainAttributeList *attrList, uint length, byte [] data);
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainItemCopyContent (IntPtr itemRef, ref SecItemClass itemClass, IntPtr attrList, ref uint length, ref IntPtr data);
-
- [DllImport (SecurityLib)]
- static extern SecStatusCode SecKeychainItemFreeContent (IntPtr attrList, IntPtr data);
-
- #endregion
-
- static SecAuthenticationType GetSecAuthenticationType (string query)
+ public static string FindInternetPassword (Uri url)
{
- if (string.IsNullOrEmpty (query))
- return SecAuthenticationType.Any;
+ // See if there is already a password there for this uri
+ var record = SecKeychainFindInternetPassword (url, out _);
- string auth = "default";
- foreach (var pair in query.Substring (1).Split (new char[] { '&' })) {
- var kvp = pair.Split (new char[] { '=' });
- if (string.Equals (kvp[0], "auth", StringComparison.InvariantCultureIgnoreCase) && kvp.Length == 2) {
- auth = kvp[1].ToLowerInvariant ();
- break;
- }
- }
+ if (record != null)
+ return NSString.FromData (record.ValueData, NSStringEncoding.UTF8);
- switch (auth) {
- case "ntlm": return SecAuthenticationType.NTLM;
- case "msn": return SecAuthenticationType.MSN;
- case "dpa": return SecAuthenticationType.DPA;
- case "rpa": return SecAuthenticationType.RPA;
- case "httpbasic": case "basic": return SecAuthenticationType.HTTPBasic;
- case "httpdigest": case "digest": return SecAuthenticationType.HTTPDigest;
- case "htmlform": case "form": return SecAuthenticationType.HTMLForm;
- case "default": return SecAuthenticationType.Default;
- default: return SecAuthenticationType.Any;
- }
+ return null;
}
- static SecProtocolType GetSecProtocolType (string protocol)
+ public static unsafe Tuple<string, string> FindInternetUserNameAndPassword (Uri uri)
{
- switch (protocol.ToLowerInvariant ()) {
- case "ftp": return SecProtocolType.FTP;
- case "ftpaccount": return SecProtocolType.FTPAccount;
- case "http": return SecProtocolType.HTTP;
- case "irc": return SecProtocolType.IRC;
- case "nntp": return SecProtocolType.NNTP;
- case "pop3": return SecProtocolType.POP3;
- case "smtp": return SecProtocolType.SMTP;
- case "socks": return SecProtocolType.SOCKS;
- case "imap": return SecProtocolType.IMAP;
- case "ldap": return SecProtocolType.LDAP;
- case "appletalk": return SecProtocolType.AppleTalk;
- case "afp": return SecProtocolType.AFP;
- case "telnet": return SecProtocolType.Telnet;
- case "ssh": return SecProtocolType.SSH;
- case "ftps": return SecProtocolType.FTPS;
- case "httpproxy": return SecProtocolType.HTTPProxy;
- case "httpsproxy": return SecProtocolType.HTTPSProxy;
- case "ftpproxy": return SecProtocolType.FTPProxy;
- case "cifs": return SecProtocolType.CIFS;
- case "smb": return SecProtocolType.SMB;
- case "rtsp": return SecProtocolType.RTSP;
- case "rtspproxy": return SecProtocolType.RTSPProxy;
- case "daap": return SecProtocolType.DAAP;
- case "eppc": return SecProtocolType.EPPC;
- case "ipp": return SecProtocolType.IPP;
- case "nntps": return SecProtocolType.NNTPS;
- case "ldaps": return SecProtocolType.LDAPS;
- case "telnets": return SecProtocolType.TelnetS;
- case "imaps": return SecProtocolType.IMAPS;
- case "ircs": return SecProtocolType.IRCS;
- case "pop3s": return SecProtocolType.POP3S;
- case "cvspserver": return SecProtocolType.CVSpserver;
- case "svn": return SecProtocolType.SVN;
- default: return SecProtocolType.Any;
- }
+ return FindInternetUserNameAndPassword (uri, GetSecProtocolType (uri.Scheme));
}
- static unsafe SecStatusCode ReplaceInternetPassword (IntPtr item, byte[] desc, byte[] passwd)
+ public static Tuple<string, string> FindInternetUserNameAndPassword (Uri url, SecProtocol protocol)
{
- fixed (byte* descPtr = desc) {
- SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [1];
- int n = 0;
+ var record = SecKeychainFindInternetPassword (url, protocol, out _);
- if (desc != null)
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Description, (uint) desc.Length, (IntPtr) descPtr);
+ if (record != null) {
- SecKeychainAttributeList attrList = new SecKeychainAttributeList (n, (IntPtr) attrs);
+ string username = record.Account != null ? NSString.FromData (record.Account, NSStringEncoding.UTF8) : null;
+ string password = record.ValueData != null ? NSString.FromData (record.ValueData, NSStringEncoding.UTF8) : null;
- return SecKeychainItemModifyAttributesAndData (item, &attrList, (uint) passwd.Length, passwd);
+ return Tuple.Create (username, password);
}
+ return null;
}
- static unsafe SecStatusCode AddInternetPassword (byte[] label, byte[] desc, SecAuthenticationType auth, byte[] user, byte[] passwd, SecProtocolType protocol, byte[] host, int port, byte[] path)
+ public static void RemoveInternetPassword (Uri url)
{
- // Note: the following code does more-or-less the same as:
- //SecKeychainAddInternetPassword (CurrentKeychain, (uint) host.Length, host, 0, null,
- // (uint) user.Length, user, (uint) path.Length, path, (ushort) port,
- // protocol, auth, (uint) passwd.Length, passwd, ref item);
-
- fixed (byte* labelPtr = label, descPtr = desc, userPtr = user, hostPtr = host, pathPtr = path) {
- SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [8];
- int* protoPtr = (int*) &protocol;
- int* authPtr = (int*) &auth;
- int* portPtr = &port;
- int n = 0;
-
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Label, (uint) label.Length, (IntPtr) labelPtr);
- if (desc != null)
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Description, (uint) desc.Length, (IntPtr) descPtr);
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Account, (uint) user.Length, (IntPtr) userPtr);
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Protocol, (uint) 4, (IntPtr) protoPtr);
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.AuthType, (uint) 4, (IntPtr) authPtr);
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Server, (uint) host.Length, (IntPtr) hostPtr);
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Port, (uint) 4, (IntPtr) portPtr);
- attrs[n++] = new SecKeychainAttribute (SecItemAttr.Path, (uint) Math.Max (path.Length - 1, 0), (IntPtr) pathPtr);
-
- SecKeychainAttributeList attrList = new SecKeychainAttributeList (n, (IntPtr) attrs);
-
- var result = SecKeychainItemCreateFromContent (SecItemClass.InternetPassword, &attrList, (uint) passwd.Length, passwd, CurrentKeychain, IntPtr.Zero, IntPtr.Zero);
-
- return result;
- }
- }
-
- public static unsafe void AddInternetPassword (Uri uri, string username, string password)
- {
- byte[] path = uri.ToPathBytes ();
- byte[] passwd = Encoding.UTF8.GetBytes (password);
- byte[] host = Encoding.UTF8.GetBytes (uri.Host);
- byte[] user = Encoding.UTF8.GetBytes (username);
- var auth = GetSecAuthenticationType (uri.Query);
- var protocol = GetSecProtocolType (uri.Scheme);
- IntPtr item = IntPtr.Zero;
- int port = uri.Port;
- byte[] desc = null;
+ var record = SecKeychainFindInternetPassword (url, out _);
- if (auth == SecAuthenticationType.HTMLForm)
- desc = WebFormPassword;
+ if (record != null) {
+ var result = SecKeyChain.Remove (record);
- // See if there is already a password there for this uri
- var result = SecKeychainFindInternetPassword (CurrentKeychain, (uint)host.Length, host, 0, null,
- (uint)user.Length, user, (uint)path.Length, path, (ushort)port,
- protocol, auth, IntPtr.Zero, IntPtr.Zero, ref item);
-
- try {
- if (result == SecStatusCode.Success) {
- // If there is, replace it with the new one
- result = ReplaceInternetPassword (item, desc, passwd);
- } else {
- var label = Encoding.UTF8.GetBytes (string.Format ("{0} ({1})", uri.Host, username));
-
- result = AddInternetPassword (label, desc, auth, user, passwd, protocol, host, port, path);
- }
- } finally {
- CFRelease (item);
+ if (result != SecStatusCode.Success)
+ throw new Exception ("Could not delete internet password from keychain: " + result.GetStatusDescription ());
}
-
- if (result != SecStatusCode.Success && result != SecStatusCode.DuplicateItem)
- throw new Exception ("Could not add internet password to keychain: " + result.GetStatusDescription ());
}
- static readonly byte[] WebFormPassword = Encoding.UTF8.GetBytes ("Web form password");
-
- public static unsafe void AddInternetPassword (Uri uri, string password) =>
- AddInternetPassword (uri, Uri.UnescapeDataString (uri.UserInfo), password);
-
- static unsafe string GetUsernameFromKeychainItemRef (IntPtr itemRef)
+ public static void RemoveInternetUserNameAndPassword (Uri url)
{
- int[] formatConstants = { (int) CssmDbAttributeFormat.String };
- int[] attributeTags = { (int) SecItemAttr.Account };
+ var record = SecKeychainFindInternetPassword (url, out _);
- fixed (int* tags = attributeTags, formats = formatConstants) {
- var attributeInfo = new SecKeychainAttributeInfo {
- Count = 1,
- Tag = tags,
- Format = formats
- };
- SecKeychainAttributeList* attributeList = null;
- SecItemClass itemClass = 0;
+ if (record != null) {
+ SecStatusCode result = SecKeyChain.Remove (record);
- try {
- SecStatusCode status = SecKeychainItemCopyAttributesAndData (itemRef, &attributeInfo, ref itemClass, &attributeList, IntPtr.Zero, IntPtr.Zero);
-
- if (status == SecStatusCode.ItemNotFound)
- throw new Exception ("Could not add internet password to keychain: " + status.GetStatusDescription ());
-
- if (status != SecStatusCode.Success)
- throw new Exception ("Could not find internet username and password: " + status.GetStatusDescription ());
-
- var userNameAttr = (SecKeychainAttribute*)attributeList->Attrs;
-
- if (userNameAttr->Length == 0)
- return null;
-
- return Marshal.PtrToStringAuto (userNameAttr->Data, (int)userNameAttr->Length);
- } finally {
- SecKeychainItemFreeAttributesAndData (attributeList, IntPtr.Zero);
- }
+ if (result != SecStatusCode.Success)
+ throw new Exception ("Could not delete internet password from keychain: " + result.GetStatusDescription ());
}
}
- public static unsafe Tuple<string, string> FindInternetUserNameAndPassword (Uri uri)
+ static SecRecord SecKeychainFindInternetPassword (Uri uri, out SecRecord searchRecord)
{
- var protocol = GetSecProtocolType (uri.Scheme);
- return FindInternetUserNameAndPassword (uri, protocol);
+ return SecKeychainFindInternetPassword (uri, GetSecProtocolType (uri.Scheme), out searchRecord);
}
- public static unsafe Tuple<string, string> FindInternetUserNameAndPassword (Uri uri, SecProtocolType protocol)
+ static SecRecord SecKeychainFindInternetPassword (Uri uri, SecProtocol protocol, out SecRecord searchRecord)
{
- byte[] path = uri.ToPathBytes ();
- byte[] host = Encoding.UTF8.GetBytes (uri.Host);
- var auth = GetSecAuthenticationType (uri.Query);
- IntPtr passwordData;
- IntPtr item = IntPtr.Zero;
- uint passwordLength = 0;
-
- var result = SecKeychainFindInternetPassword (
- CurrentKeychain, (uint) host.Length, host, 0, null,
- 0, null, (uint) path.Length, path, (ushort) uri.Port,
- protocol, auth, out passwordLength, out passwordData, ref item);
-
- try {
- if (result != SecStatusCode.Success)
- return null;
+ // Look for an internet password for the given protocol and auth mechanism
+ searchRecord = uri.ToSecRecord ();
+ if (protocol != SecProtocol.Invalid)
+ searchRecord.Protocol = protocol;
- var username = GetUsernameFromKeychainItemRef (item);
- return Tuple.Create (username, Marshal.PtrToStringAuto (passwordData, (int) passwordLength));
- } finally {
- SecKeychainItemFreeContent (IntPtr.Zero, passwordData);
- CFRelease (item);
- }
- }
+ var data = SecKeyChain.QueryAsRecord (searchRecord, out SecStatusCode code);
- public static string FindInternetPassword (Uri uri)
- {
- byte[] path = uri.ToPathBytes ();
- byte[] user = Encoding.UTF8.GetBytes (Uri.UnescapeDataString (uri.UserInfo));
- byte[] host = Encoding.UTF8.GetBytes (uri.Host);
- var auth = GetSecAuthenticationType (uri.Query);
- var protocol = GetSecProtocolType (uri.Scheme);
- IntPtr passwordData = IntPtr.Zero;
- IntPtr item = IntPtr.Zero;
- uint passwordLength = 0;
-
- try {
- // Look for an internet password for the given protocol and auth mechanism
- var result = SecKeychainFindInternetPassword (CurrentKeychain, (uint)host.Length, host, 0, null,
- (uint)user.Length, user, (uint)path.Length, path, (ushort)uri.Port,
- protocol, auth, out passwordLength, out passwordData, ref item);
-
- // Fall back to looking for a password for SecProtocolType.Any && SecAuthenticationType.Any
- if (result == SecStatusCode.ItemNotFound && protocol != SecProtocolType.Any)
- result = SecKeychainFindInternetPassword (CurrentKeychain, (uint)host.Length, host, 0, null,
- (uint)user.Length, user, (uint)path.Length, path, (ushort)uri.Port,
- 0, auth, out passwordLength, out passwordData, ref item);
+ if (code == SecStatusCode.ItemNotFound) {
+ // Fall back to looking for a password without use SecProtocol && SecAuthenticationType
+ searchRecord.Protocol = SecProtocol.Http; // Http is the default used by SecKeyChain internally
+ searchRecord.AuthenticationType = SecAuthenticationType.Default;
- if (result != SecStatusCode.Success)
- return null;
+ data = SecKeyChain.QueryAsRecord (searchRecord, out code);
+ }
- return Marshal.PtrToStringAuto (passwordData, (int)passwordLength);
- } finally {
- CFRelease (item);
+ if (code != SecStatusCode.Success)
+ return null;
- SecKeychainItemFreeContent (IntPtr.Zero, passwordData);
- }
+ return data;
}
- public static void RemoveInternetPassword (Uri uri)
+ static readonly string WebFormPassword = "Web form password";
+
+ static SecRecord ToSecRecord (this Uri uri, string username = null, string password = null)
{
- byte[] path = uri.ToPathBytes ();
- byte[] user = Encoding.UTF8.GetBytes (Uri.UnescapeDataString (uri.UserInfo));
- byte[] host = Encoding.UTF8.GetBytes (uri.Host);
- var auth = GetSecAuthenticationType (uri.Query);
+ var record = new SecRecord (SecKind.InternetPassword) {
+ Server = uri.Host,
+ Path = string.Join (string.Empty, uri.Segments),
+ Port = uri.Port,
+ };
var protocol = GetSecProtocolType (uri.Scheme);
- IntPtr item = IntPtr.Zero;
+ if (protocol != SecProtocol.Invalid)
+ record.Protocol = protocol;
+ var authType = GetSecAuthenticationType (uri.Query);
+ if (authType != SecAuthenticationType.Default)
+ record.AuthenticationType = authType;
- // Look for an internet password for the given protocol and auth mechanism
- var result = SecKeychainFindInternetPassword (CurrentKeychain, (uint) host.Length, host, 0, null,
- (uint) user.Length, user, (uint) path.Length, path, (ushort) uri.Port,
- protocol, auth, IntPtr.Zero, IntPtr.Zero, ref item);
+ if (record.AuthenticationType == SecAuthenticationType.HtmlForm)
+ record.Description = WebFormPassword;
- // Fall back to looking for a password for SecProtocolType.Any && SecAuthenticationType.Any
- if (result == SecStatusCode.ItemNotFound && protocol != SecProtocolType.Any)
- result = SecKeychainFindInternetPassword (CurrentKeychain, (uint) host.Length, host, 0, null,
- (uint) user.Length, user, (uint) path.Length, path, (ushort) uri.Port,
- 0, auth, IntPtr.Zero, IntPtr.Zero, ref item);
+ var account = Uri.UnescapeDataString (uri.UserInfo);
+ if (string.IsNullOrEmpty (account)) // account from Uri has always priority
+ account = username;
- try {
- if (result != SecStatusCode.Success)
- return;
+ if (!string.IsNullOrEmpty (account))
+ record.Account = account;
- SecKeychainItemDelete (item);
- } finally {
- CFRelease (item);
- }
+ if (password != null)
+ record.ValueData = NSData.FromString (password);
+
+ return record;
}
- public static void RemoveInternetUserNameAndPassword (Uri uri)
+ static SecProtocol GetSecProtocolType (string protocol)
{
- byte[] path = uri.ToPathBytes ();
- byte[] host = Encoding.UTF8.GetBytes (uri.Host);
- var auth = GetSecAuthenticationType (uri.Query);
- IntPtr item = IntPtr.Zero;
-
- var result = SecKeychainFindInternetPassword (
- CurrentKeychain, (uint) host.Length, host, 0, null,
- 0, null, (uint) path.Length, path, (ushort) uri.Port,
- GetSecProtocolType (uri.Scheme), auth, IntPtr.Zero, IntPtr.Zero, ref item);
-
- try {
- if (result != SecStatusCode.Success)
- return;
-
- result = SecKeychainItemDelete (item);
- } finally {
- CFRelease (item);
+ switch (protocol.ToLowerInvariant ()) {
+ case "ftp": return SecProtocol.Ftp;
+ case "ftpaccount": return SecProtocol.FtpAccount;
+ case "http": return SecProtocol.Http;
+ case "https": return SecProtocol.Https;
+ case "irc": return SecProtocol.Irc;
+ case "nntp": return SecProtocol.Nntp;
+ case "pop3": return SecProtocol.Pop3;
+ case "pop3s": return SecProtocol.Pop3s;
+ case "smtp": return SecProtocol.Smtp;
+ case "socks": return SecProtocol.Socks;
+ case "imap": return SecProtocol.Imap;
+ case "imaps": return SecProtocol.Imaps;
+ case "ldap": return SecProtocol.Ldap;
+ case "ldaps": return SecProtocol.Ldaps;
+ case "appletalk": return SecProtocol.AppleTalk;
+ case "afp": return SecProtocol.Afp;
+ case "telnet": return SecProtocol.Telnet;
+ case "ssh": return SecProtocol.Ssh;
+ case "ftps": return SecProtocol.Ftps;
+ case "httpproxy": return SecProtocol.HttpProxy;
+ case "httpsproxy": return SecProtocol.HttpProxy;
+ case "ftpproxy": return SecProtocol.FtpProxy;
+ case "smb": return SecProtocol.Smb;
+ case "rtsp": return SecProtocol.Rtsp;
+ case "rtspproxy": return SecProtocol.RtspProxy;
+ case "daap": return SecProtocol.Daap;
+ case "eppc": return SecProtocol.Eppc;
+ case "ipp": return SecProtocol.Ipp;
+ case "nntps": return SecProtocol.Nntps;
+ case "telnets": return SecProtocol.Telnets;
+ case "ircs": return SecProtocol.Ircs;
+ default: return SecProtocol.Invalid;
}
}
- static byte [] ToPathBytes (this Uri uri)
+ static SecAuthenticationType GetSecAuthenticationType (string query)
{
- var pathStr = string.Join (string.Empty, uri.Segments);
- byte[] path = pathStr.Length > 0 ? pathStr.ToNullTerminatedUtf8 (1) : Array.Empty<byte> (); // don't include the leading '/'
- return path;
- }
+ if (string.IsNullOrEmpty (query))
+ return SecAuthenticationType.Default;
- // It seems that keychain APIs require null terminated native strings.
- internal static byte [] ToNullTerminatedUtf8 (this string str, int offset = 0)
- {
- unsafe {
- fixed (char* p = str) {
- return ToNullTerminatedUtf8 (p + offset, str.Length - offset);
+ string auth = "default";
+ foreach (var pair in query.Substring (1).Split (new char [] { '&' })) {
+ var kvp = pair.Split (new char [] { '=' });
+ if (string.Equals (kvp [0], "auth", StringComparison.InvariantCultureIgnoreCase) && kvp.Length == 2) {
+ auth = kvp [1].ToLowerInvariant ();
+ break;
}
}
- }
-
- static unsafe byte [] ToNullTerminatedUtf8 (char* p, int len)
- {
- if (len == 0)
- return Array.Empty<byte> ();
- var byteCount = Encoding.UTF8.GetByteCount (p, len);
- var bytes = new byte [byteCount + 1];
- fixed (byte* b = bytes) {
- Encoding.UTF8.GetBytes (p, len, b, byteCount);
+ switch (auth) {
+ case "ntlm": return SecAuthenticationType.Ntlm;
+ case "msn": return SecAuthenticationType.Msn;
+ case "dpa": return SecAuthenticationType.Dpa;
+ case "rpa": return SecAuthenticationType.Rpa;
+ case "httpbasic": case "basic": return SecAuthenticationType.HttpBasic;
+ case "httpdigest": case "digest": return SecAuthenticationType.HttpDigest;
+ case "htmlform": case "form": return SecAuthenticationType.HtmlForm;
+ default: return SecAuthenticationType.Default;
}
- return bytes;
}
}
-
- enum SecItemClass : uint
- {
- InternetPassword = 1768842612, // 'inet'
- GenericPassword = 1734700656, // 'genp'
- AppleSharePassword = 1634953328, // 'ashp'
- Certificate = 0x80000000 + 0x1000,
- PublicKey = 0x0000000A + 5,
- PrivateKey = 0x0000000A + 6,
- SymmetricKey = 0x0000000A + 7
- }
-
- enum SecItemAttr : int
- {
- CreationDate = 1667522932,
- ModDate = 1835295092,
- Description = 1684370275,
- Comment = 1768123764,
- Creator = 1668445298,
- Type = 1954115685,
- ScriptCode = 1935897200,
- Label = 1818321516,
- Invisible = 1768846953,
- Negative = 1852139361,
- CustomIcon = 1668641641,
- Account = 1633903476,
- Service = 1937138533,
- Generic = 1734700641,
- SecurityDomain = 1935961454,
- Server = 1936881266,
- AuthType = 1635023216,
- Port = 1886351988,
- Path = 1885434984,
- Volume = 1986817381,
- Address = 1633969266,
- Signature = 1936943463,
- Protocol = 1886675820,
- CertificateType = 1668577648,
- CertificateEncoding = 1667591779,
- CrlType = 1668445296,
- CrlEncoding = 1668443747,
- Alias = 1634494835,
- }
-
- enum SecAuthenticationType : int
- {
- NTLM = 1835824238,
- MSN = 1634628461,
- DPA = 1633775716,
- RPA = 1633775730,
- HTTPBasic = 1886680168,
- HTTPDigest = 1685353576,
- HTMLForm = 1836216166,
- Default = 1953261156,
- Any = 0
- }
-
- public enum SecProtocolType : int
- {
- FTP = 1718906912,
- FTPAccount = 1718906977,
- HTTP = 1752462448,
- IRC = 1769104160,
- NNTP = 1852732528,
- POP3 = 1886351411,
- SMTP = 1936553072,
- SOCKS = 1936685088,
- IMAP = 1768776048,
- LDAP = 1818517872,
- AppleTalk = 1635019883,
- AFP = 1634103328,
- Telnet = 1952803950,
- SSH = 1936943136,
- FTPS = 1718906995,
- HTTPProxy = 1752461432,
- HTTPSProxy = 1752462200,
- FTPProxy = 1718907000,
- CIFS = 1667851891,
- SMB = 1936548384,
- RTSP = 1920234352,
- RTSPProxy = 1920234360,
- DAAP = 1684103536,
- EPPC = 1701867619,
- IPP = 1768976416,
- NNTPS = 1853124723,
- LDAPS = 1818521715,
- TelnetS = 1952803955,
- IMAPS = 1768779891,
- IRCS = 1769104243,
- POP3S = 1886351475,
- CVSpserver = 1668707184,
- SVN = 1937141280,
- Any = 0
- }
-
- enum CssmDbAttributeFormat : int
- {
- String = 0,
- Int32 = 1,
- UInt32 = 2,
- BigNum = 3,
- Real = 4,
- DateTime = 5,
- Blob = 6,
- MultiUInt32 = 7,
- Complex = 8
- }
-}
+} \ No newline at end of file
diff --git a/main/src/addins/MacPlatform/MacPlatform.cs b/main/src/addins/MacPlatform/MacPlatform.cs
index a5a54ba328..6dfb61f82f 100644
--- a/main/src/addins/MacPlatform/MacPlatform.cs
+++ b/main/src/addins/MacPlatform/MacPlatform.cs
@@ -57,6 +57,7 @@ using Xwt.Mac;
using MonoDevelop.Components.Mac;
using System.Reflection;
using MacPlatform;
+using MonoDevelop.Projects;
namespace MonoDevelop.MacIntegration
{
@@ -582,6 +583,14 @@ namespace MonoDevelop.MacIntegration
// Gtk.Rc.ParseString (gtkrc);
}
+ static TimeToCodeMetadata.DocumentType GetDocumentTypeFromFilename (string filename)
+ {
+ if (Projects.Services.ProjectService.IsWorkspaceItemFile (filename) || Projects.Services.ProjectService.IsSolutionItemFile (filename)) {
+ return TimeToCodeMetadata.DocumentType.Solution;
+ }
+ return TimeToCodeMetadata.DocumentType.File;
+ }
+
void GlobalSetup ()
{
//FIXME: should we remove these when finalizing?
@@ -628,21 +637,30 @@ namespace MonoDevelop.MacIntegration
};
ApplicationEvents.OpenDocuments += delegate (object sender, ApplicationDocumentEventArgs e) {
- //OpenFiles may pump the mainloop, but can't do that from an AppleEvent, so use a brief timeout
- GLib.Timeout.Add (0, delegate {
+ //OpenFiles may pump the mainloop, but can't do that from an AppleEvent
+ GLib.Idle.Add (delegate {
Ide.WelcomePage.WelcomePageService.HideWelcomePageOrWindow ();
- IdeApp.ReportTimeToCode = true;
+ var trackTTC = IdeApp.StartTimeToCodeLoadTimer ();
IdeApp.OpenFiles (e.Documents.Select (
- doc => new FileOpenInformation (doc.Key, null, doc.Value, 1, OpenDocumentOptions.DefaultInternal))
- );
+ doc => new FileOpenInformation (doc.Key, null, doc.Value, 1, OpenDocumentOptions.DefaultInternal)),
+ null
+ ).ContinueWith ((result) => {
+ if (!trackTTC) {
+ return;
+ }
+
+ var firstFile = e.Documents.First ().Key;
+
+ IdeApp.TrackTimeToCode (GetDocumentTypeFromFilename (firstFile));
+ });
return false;
});
e.Handled = true;
};
ApplicationEvents.OpenUrls += delegate (object sender, ApplicationUrlEventArgs e) {
- GLib.Timeout.Add (0, delegate {
- IdeApp.ReportTimeToCode = true;
+ GLib.Idle.Add (delegate {
+ var trackTTC = IdeApp.StartTimeToCodeLoadTimer ();
// Open files via the monodevelop:// URI scheme, compatible with the
// common TextMate scheme: http://blog.macromates.com/2007/the-textmate-url-scheme/
IdeApp.OpenFiles (e.Urls.Select (url => {
@@ -666,7 +684,14 @@ namespace MonoDevelop.MacIntegration
LoggingService.LogError ("Invalid TextMate URI: " + url, ex);
return null;
}
- }).Where (foi => foi != null));
+ }).Where (foi => foi != null), null).ContinueWith ((result) => {
+ if (!trackTTC) {
+ return;
+ }
+ var firstFile = e.Urls.First ();
+
+ IdeApp.TrackTimeToCode (GetDocumentTypeFromFilename (firstFile));
+ });
return false;
});
};
@@ -970,7 +995,7 @@ namespace MonoDevelop.MacIntegration
public override Window GetParentForModalWindow ()
{
- return NSApplication.SharedApplication.KeyWindow ?? NSApplication.SharedApplication.MainWindow;
+ return NSApplication.SharedApplication.ModalWindow ?? NSApplication.SharedApplication.KeyWindow ?? NSApplication.SharedApplication.MainWindow;
}
public override Window GetFocusedTopLevelWindow ()
diff --git a/main/src/addins/MacPlatform/MacProxyCredentialProvider.cs b/main/src/addins/MacPlatform/MacProxyCredentialProvider.cs
index c8a49b7cba..ad74568afa 100644
--- a/main/src/addins/MacPlatform/MacProxyCredentialProvider.cs
+++ b/main/src/addins/MacPlatform/MacProxyCredentialProvider.cs
@@ -34,6 +34,7 @@ using AppKit;
using CoreGraphics;
using Foundation;
using MonoDevelop.MacInterop;
+using Security;
namespace MonoDevelop.MacIntegration
{
@@ -65,11 +66,11 @@ namespace MonoDevelop.MacIntegration
static ICredentials GetSystemProxyCredentials (Uri uri)
{
- var kind = SecProtocolType.Any;
+ var kind = SecProtocol.Http;
if (uri.Scheme == "http")
- kind = SecProtocolType.HTTPProxy;
+ kind = SecProtocol.HttpProxy;
else if (uri.Scheme == "https")
- kind = SecProtocolType.HTTPSProxy;
+ kind = SecProtocol.HttpsProxy;
//TODO: get username from SystemConfiguration APIs so we don't trigger a double auth prompt
var existing = Keychain.FindInternetUserNameAndPassword (uri, kind);
diff --git a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs
index 4347eb730d..0abaff837d 100644
--- a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs
+++ b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs
@@ -24,10 +24,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
+using System.Linq;
using System.Threading.Tasks;
using MonoDevelop.Core;
using MonoDevelop.Core.Execution;
using MonoDevelop.DotNetCore;
+using MonoDevelop.Ide;
using MonoDevelop.Projects;
namespace MonoDevelop.AspNetCore
@@ -35,6 +37,8 @@ namespace MonoDevelop.AspNetCore
[ExportProjectModelExtension]
class AspNetCoreProjectExtension : DotNetCoreProjectExtension
{
+ public const string TypeScriptCompile = "TypeScriptCompile";
+
protected override ProjectRunConfiguration OnCreateRunConfiguration (string name)
{
return new AspNetCoreRunConfiguration (name);
@@ -96,5 +100,13 @@ namespace MonoDevelop.AspNetCore
}
await base.OnExecute (monitor, context, configuration, runConfiguration);
}
+
+ protected override string OnGetDefaultBuildAction (string fileName)
+ {
+ if (DesktopService.GetMimeTypeInheritanceChainForFile (fileName).Contains ("text/x-typescript"))
+ return TypeScriptCompile;
+
+ return base.OnGetDefaultBuildAction (fileName);
+ }
}
}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.Visualizer/TextVisualizer.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.Visualizer/TextVisualizer.cs
index 64b1153aea..ef9bda47f8 100644
--- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.Visualizer/TextVisualizer.cs
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.Visualizer/TextVisualizer.cs
@@ -112,7 +112,7 @@ namespace MonoDevelop.Debugger.Visualizer
if (value.TypeName == "string") {
rawString = value.GetRawValue (options) as RawValueString;
- length = rawString.Length;
+ length = rawString?.Length ?? 0;
offset = 0;
if (length > 0) {
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebugCommands.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebugCommands.cs
index 27259be283..c508b4c654 100644
--- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebugCommands.cs
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebugCommands.cs
@@ -444,6 +444,7 @@ namespace MonoDevelop.Debugger
protected override void Update (CommandInfo info)
{
info.Visible = DebuggingService.IsFeatureSupported (DebuggerFeatures.Disassembly);
+ info.Enabled = IdeApp.Workspace.IsOpen;
}
}
@@ -497,7 +498,7 @@ namespace MonoDevelop.Debugger
protected override void Update (CommandInfo info)
{
info.Visible = DebuggingService.IsFeatureSupported (DebuggerFeatures.Breakpoints);
- info.Enabled = !DebuggingService.Breakpoints.IsReadOnly;
+ info.Enabled = !DebuggingService.Breakpoints.IsReadOnly && IdeApp.Workspace.IsOpen;
}
}
@@ -517,7 +518,7 @@ namespace MonoDevelop.Debugger
protected override void Update (CommandInfo info)
{
info.Visible = DebuggingService.IsFeatureSupported (DebuggerFeatures.Breakpoints);
- info.Enabled = !DebuggingService.Breakpoints.IsReadOnly;
+ info.Enabled = !DebuggingService.Breakpoints.IsReadOnly && IdeApp.Workspace.IsOpen;
}
}
@@ -537,7 +538,7 @@ namespace MonoDevelop.Debugger
protected override void Update (CommandInfo info)
{
info.Visible = DebuggingService.IsFeatureSupported (DebuggerFeatures.Catchpoints);
- info.Enabled = !DebuggingService.Breakpoints.IsReadOnly;
+ info.Enabled = !DebuggingService.Breakpoints.IsReadOnly && IdeApp.Workspace.IsOpen;
}
}
@@ -550,6 +551,11 @@ namespace MonoDevelop.Debugger
breakpointsPad.BringToFront ();
}
}
+
+ protected override void Update (CommandInfo info)
+ {
+ info.Enabled = IdeApp.Workspace.IsOpen;
+ }
}
class RunToCursorHandler : CommandHandler
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs
index 456df5df01..b4ac8469c8 100644
--- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs
@@ -1,4 +1,4 @@
-//
+//
// ExceptionCaughtDialog.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
@@ -60,7 +60,7 @@ namespace MonoDevelop.Debugger
protected Label ExceptionMessageLabel { get; private set; }
- protected Label ExceptionHelpLinkLabel { get; private set; }
+ protected Button ExceptionHelpLinkButton { get; private set; }
protected Label ExceptionTypeLabel { get; private set; }
@@ -105,8 +105,8 @@ namespace MonoDevelop.Debugger
ExceptionTypeLabel = new Label { Xalign = 0.0f, Selectable = true, CanFocus = false };
ExceptionMessageLabel = new Label { Wrap = true, Xalign = 0.0f, Selectable = true, CanFocus = false };
- ExceptionHelpLinkLabel = new Label { Wrap = true, Xalign = 0.0f, Selectable = true, CanFocus = false, UseMarkup = true, LineWrapMode = Pango.WrapMode.Char };
- ExceptionHelpLinkLabel.Name = "exception_help_link_label";
+ ExceptionHelpLinkButton = new Button { HasFocus = true, Xalign = 0, Relief = ReliefStyle.None, BorderWidth = 0 };
+ ExceptionHelpLinkButton.Name = "exception_help_link_label";
Gtk.Rc.ParseString (@"style ""exception-help-link-label""
{
GtkWidget::link-color = ""#ffffff""
@@ -114,23 +114,26 @@ namespace MonoDevelop.Debugger
}
widget ""*.exception_help_link_label"" style ""exception-help-link-label""
");
-
var textColor = Styles.ExceptionCaughtDialog.HeaderTextColor.ToGdkColor ();
+ var headerColor = Styles.ExceptionCaughtDialog.HeaderBackgroundColor.ToGdkColor ();
+
+ ExceptionHelpLinkButton.ModifyBg (StateType.Selected, headerColor);
+
+ ExceptionHelpLinkButton.Clicked += ExceptionHelpLinkLabel_Clicked;
+ ExceptionHelpLinkButton.KeyPressEvent += EventBoxLink_KeyPressEvent;
- ExceptionHelpLinkLabel.ModifyBase (StateType.Prelight, Styles.ExceptionCaughtDialog.HeaderBackgroundColor.ToGdkColor ());
- ExceptionHelpLinkLabel.SetLinkHandler ((str) => IdeServices.DesktopService.ShowUrl (str));
ExceptionTypeLabel.ModifyFg (StateType.Normal, textColor);
ExceptionMessageLabel.ModifyFg (StateType.Normal, textColor);
- ExceptionHelpLinkLabel.ModifyFg (StateType.Normal, textColor);
+ ExceptionHelpLinkButton.ModifyFg (StateType.Normal, textColor);
if (Platform.IsWindows) {
ExceptionTypeLabel.ModifyFont (Pango.FontDescription.FromString ("bold 19"));
ExceptionMessageLabel.ModifyFont (Pango.FontDescription.FromString ("10"));
- ExceptionHelpLinkLabel.ModifyFont (Pango.FontDescription.FromString ("10"));
+ ExceptionHelpLinkButton.ModifyFont (Pango.FontDescription.FromString ("10"));
} else {
ExceptionTypeLabel.ModifyFont (Pango.FontDescription.FromString ("21"));
ExceptionMessageLabel.ModifyFont (Pango.FontDescription.FromString ("12"));
- ExceptionHelpLinkLabel.ModifyFont (Pango.FontDescription.FromString ("12"));
+ ExceptionHelpLinkButton.ModifyFont (Pango.FontDescription.FromString ("12"));
}
//Force rendering of background with EventBox
@@ -141,8 +144,13 @@ widget ""*.exception_help_link_label"" style ""exception-help-link-label""
leftVBox.PackStart (icon, false, false, (uint)(Platform.IsWindows ? 5 : 0)); // as we change frame.BorderWidth below, we need to compensate
rightVBox.PackStart (ExceptionTypeLabel, false, false, (uint)(Platform.IsWindows ? 0 : 2));
+
+ var exceptionHContainer = new HBox ();
+ exceptionHContainer.PackStart (ExceptionHelpLinkButton, false, false, 0);
+ exceptionHContainer.PackStart (new Fixed (), true, true, 0);
+
rightVBox.PackStart (ExceptionMessageLabel, true, true, (uint)(Platform.IsWindows ? 6 : 5));
- rightVBox.PackStart (ExceptionHelpLinkLabel, false, false, 2);
+ rightVBox.PackStart (exceptionHContainer, false, false, 2);
hBox.PackStart (leftVBox, false, false, (uint)(Platform.IsWindows ? 5 : 0)); // as we change frame.BorderWidth below, we need to compensate
hBox.PackStart (rightVBox, true, true, (uint)(Platform.IsWindows ? 5 : 10));
@@ -155,19 +163,27 @@ widget ""*.exception_help_link_label"" style ""exception-help-link-label""
eventBox.Add (frame);
eventBox.ShowAll ();
- eventBox.ModifyBg (StateType.Normal, Styles.ExceptionCaughtDialog.HeaderBackgroundColor.ToGdkColor ());
+ eventBox.ModifyBg (StateType.Normal, headerColor);
return eventBox;
}
+ void ExceptionHelpLinkLabel_Clicked (object sender, EventArgs e) => DesktopService.ShowUrl (exceptionHelpLink);
+
+ void EventBoxLink_KeyPressEvent (object o, KeyPressEventArgs args)
+ {
+ if (args.Event.Key == Gdk.Key.KP_Enter || args.Event.Key == Gdk.Key.KP_Space)
+ DesktopService.ShowUrl (exceptionHelpLink);
+ }
+
+ void EventBoxLink_ExceptionHelpLink (object o, ButtonPressEventArgs args) => DesktopService.ShowUrl (exceptionHelpLink);
+
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
{
base.OnSizeAllocated (allocation);
ExceptionMessageLabel.WidthRequest = rightVBox.Allocation.Width;
- ExceptionHelpLinkLabel.WidthRequest = rightVBox.Allocation.Width;
if (vboxAroundInnerExceptionMessage != null) {
InnerExceptionMessageLabel.WidthRequest = vboxAroundInnerExceptionMessage.Allocation.Width;
- InnerExceptionHelpLinkLabel.WidthRequest = vboxAroundInnerExceptionMessage.Allocation.Width;
}
}
@@ -180,6 +196,7 @@ widget ""*.exception_help_link_label"" style ""exception-help-link-label""
ExceptionValueTreeView.AllowExpanding = true;
ExceptionValueTreeView.AllowPinning = false;
ExceptionValueTreeView.AllowEditing = false;
+ ExceptionValueTreeView.CanFocus = true;
ExceptionValueTreeView.AllowAdding = false;
ExceptionValueTreeView.RulesHint = true;
ExceptionValueTreeView.ModifyFont (Pango.FontDescription.FromString (Platform.IsWindows ? "9" : "11"));
@@ -189,6 +206,7 @@ widget ""*.exception_help_link_label"" style ""exception-help-link-label""
var scrolled = new ScrolledWindow {
HeightRequest = 180,
+ CanFocus = true,
HscrollbarPolicy = PolicyType.Automatic,
VscrollbarPolicy = PolicyType.Automatic
};
@@ -230,7 +248,7 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
expander.Child = widget;
expander.Spacing = 0;
expander.Show ();
- expander.CanFocus = false;
+ expander.CanFocus = true;
expander.UseMarkup = true;
expander.Expanded = true;
expander.Activated += Expander_Activated;
@@ -399,7 +417,7 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
Label InnerExceptionTypeLabel;
Label InnerExceptionMessageLabel;
- Label InnerExceptionHelpLinkLabel;
+ Button InnerExceptionHelpLinkButton;
Widget CreateInnerExceptionMessage ()
{
@@ -425,24 +443,39 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
InnerExceptionMessageLabel.Xalign = 0;
InnerExceptionMessageLabel.ModifyFont (Pango.FontDescription.FromString (Platform.IsWindows ? "9" : "11"));
- InnerExceptionHelpLinkLabel = new Label ();
- InnerExceptionHelpLinkLabel.UseMarkup = true;
- InnerExceptionHelpLinkLabel.Wrap = true;
- InnerExceptionHelpLinkLabel.LineWrapMode = Pango.WrapMode.Char;
- InnerExceptionHelpLinkLabel.Selectable = true;
- InnerExceptionHelpLinkLabel.CanFocus = false;
- InnerExceptionHelpLinkLabel.Xalign = 0;
- InnerExceptionHelpLinkLabel.ModifyFont (Pango.FontDescription.FromString (Platform.IsWindows ? "9" : "11"));
- InnerExceptionHelpLinkLabel.SetLinkHandler ((str) => IdeServices.DesktopService.ShowUrl (str));
+ InnerExceptionHelpLinkButton = new Button {
+ CanFocus = true,
+ BorderWidth = 0,
+ Relief = ReliefStyle.Half,
+ Xalign = 0
+ };
+ InnerExceptionHelpLinkButton.ModifyFont (Pango.FontDescription.FromString (Platform.IsWindows ? "9" : "11"));
+ InnerExceptionHelpLinkButton.KeyPressEvent += InnerExceptionHelpLinkLabel_KeyPressEvent;
+ InnerExceptionHelpLinkButton.Clicked += InnerExceptionHelpLinkLabel_Pressed;
+
+ InnerExceptionHelpLinkButton.ModifyBg (StateType.Selected, Styles.ExceptionCaughtDialog.TreeSelectedBackgroundColor.ToGdkColor ());
vboxAroundInnerExceptionMessage.PackStart (hbox, false, true, 0);
vboxAroundInnerExceptionMessage.PackStart (InnerExceptionMessageLabel, true, true, 10);
- vboxAroundInnerExceptionMessage.PackStart (InnerExceptionHelpLinkLabel, true, true, 2);
+
+ var innerExceptionHContainer = new HBox ();
+
+ innerExceptionHContainer.PackStart (InnerExceptionHelpLinkButton, false, false, 0);
+ innerExceptionHContainer.PackStart (new Fixed (), true, true, 0);
+
+ vboxAroundInnerExceptionMessage.PackStart (innerExceptionHContainer, true, true, 2);
hboxMain.PackStart (vboxAroundInnerExceptionMessage, true, true, 10);
hboxMain.ShowAll ();
return hboxMain;
}
+ void InnerExceptionHelpLinkLabel_Pressed (object sender, EventArgs e) => DesktopService.ShowUrl (innerExceptionHelpLink);
+ void InnerExceptionHelpLinkLabel_KeyPressEvent (object o, KeyPressEventArgs args)
+ {
+ if (args.Event.Key == Gdk.Key.KP_Enter || args.Event.Key == Gdk.Key.KP_Space)
+ IdeServices.DesktopService.ShowUrl (innerExceptionHelpLink);
+ }
+
TreeStore InnerExceptionsStore;
class InnerExceptionsTree : TreeView
@@ -606,14 +639,19 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
InnerExceptionTypeLabel.Markup = "<b>" + GLib.Markup.EscapeText (ex.Type) + "</b>";
InnerExceptionMessageLabel.Text = ex.Message;
if (!string.IsNullOrEmpty (ex.HelpLink)) {
- InnerExceptionHelpLinkLabel.Markup = GetHelpLinkMarkup (ex);
- InnerExceptionHelpLinkLabel.Show ();
+ InnerExceptionHelpLinkButton.Label = GettextCatalog.GetString ("Read More…");
+ innerExceptionHelpLink = ex.HelpLink;
+ InnerExceptionHelpLinkButton.Show ();
} else {
- InnerExceptionHelpLinkLabel.Hide ();
+ innerExceptionHelpLink = string.Empty;
+ InnerExceptionHelpLinkButton.Hide ();
}
}
}
+ string innerExceptionHelpLink;
+ string exceptionHelpLink;
+
void UpdateDisplay ()
{
if (destroyed)
@@ -622,20 +660,16 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
ExceptionTypeLabel.Text = exception.Type;
ExceptionMessageLabel.Text = exception.Message ?? string.Empty;
if (!string.IsNullOrEmpty (exception.HelpLink)) {
- ExceptionHelpLinkLabel.Show ();
- ExceptionHelpLinkLabel.Markup = GetHelpLinkMarkup (exception);
+ ExceptionHelpLinkButton.Show ();
+ exceptionHelpLink = exception.HelpLink;
+ ExceptionHelpLinkButton.Label = GettextCatalog.GetString ("More information");
} else {
- ExceptionHelpLinkLabel.Hide ();
+ ExceptionHelpLinkButton.Hide ();
}
UpdateSelectedException (exception);
}
- internal static string GetHelpLinkMarkup (ExceptionInfo exception)
- {
- return $"<a href=\"{System.Security.SecurityElement.Escape (exception.HelpLink)}\">{GettextCatalog.GetString ("More information")}</a>";
- }
-
void ExceptionChanged (object sender, EventArgs e)
{
Application.Invoke ((o, args) => {
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Projects/ProjectFileDescriptor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Projects/ProjectFileDescriptor.cs
index 6a08c70968..b51ee3c13b 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Projects/ProjectFileDescriptor.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Projects/ProjectFileDescriptor.cs
@@ -51,16 +51,16 @@ namespace MonoDevelop.DesignerSupport
void OnFilePropertyChangedInProject (object sender, ProjectFileEventArgs args)
{
- var pad = IdeApp.Workbench.GetPad <PropertyPad> ();
+ var pad = IdeApp.Workbench.GetPad <IPropertyPad> ();
if (pad == null)
return;
- var grid = ((PropertyPad)pad.Content).PropertyGrid;
- if (grid.IsEditing)
+ var propertyPad = (IPropertyPad)pad.Content;
+ if (propertyPad.IsGridEditing)
return;
if (args.Any (arg => arg.ProjectFile == file))
- grid.Populate (saveEditSession: false);
+ propertyPad.PopulateGrid (saveEditSession: false);
}
void IDisposable.Dispose ()
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs
index ff77360350..6b62628491 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs
@@ -1,8 +1,9 @@
#if MAC
using AppKit;
using MonoDevelop.Ide;
+using Xamarin.PropertyEditing.Mac;
-namespace MonoDevelop.DesignerSupport.Toolbox
+namespace MonoDevelop.DesignerSupport
{
static class Styles
{
@@ -28,12 +29,14 @@ namespace MonoDevelop.DesignerSupport.Toolbox
public static void LoadStyles ()
{
if (IdeApp.Preferences.UserInterfaceTheme == Theme.Light) {
+ PropertyEditorPanel.ThemeManager.Theme = Xamarin.PropertyEditing.Themes.PropertyEditorTheme.Light;
HeaderBackgroundColor = NSColor.FromRgb (0.98f, 0.98f, 0.98f);
HeaderBorderBackgroundColor = NSColor.FromRgb (0.96f, 0.96f, 0.96f);
LabelSelectedForegroundColor = NSColor.Highlight;
ToolbarBackgroundColor = NSColor.White;
CellBackgroundSelectedColor = NSColor.FromRgb (0.36f, 0.54f, 0.90f);
} else {
+ PropertyEditorPanel.ThemeManager.Theme = Xamarin.PropertyEditing.Themes.PropertyEditorTheme.Dark;
CellBackgroundSelectedColor = NSColor.FromRgb (0.38f, 0.55f, 0.91f);
HeaderBackgroundColor = NSColor.FromRgb (0.29f, 0.29f, 0.29f);
HeaderBorderBackgroundColor = NSColor.FromRgb (0.29f, 0.29f, 0.29f);
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj
index 8526f08323..98dca9926b 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj
@@ -18,10 +18,18 @@
<Private>False</Private>
</Reference>
<ProjectReference Include="..\..\..\external\xwt\Xwt.XamMac\Xwt.XamMac.csproj">
- <Project>{B7C1673E-5124-4BE5-8D21-EC8B12F85B6B}</Project>
+ <Project>{B7C1673E-5124-4BE5-8D21-EC8B12F85B6B}</Project>
<Name>Xwt.XamMac</Name>
<Private>False</Private>
- </ProjectReference>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\external\Xamarin.PropertyEditing\Xamarin.PropertyEditing.Mac\Xamarin.PropertyEditing.Mac.csproj">
+ <Project>{E8F4F0EB-C2B1-4116-8459-E076E0E0E485}</Project>
+ <Name>Xamarin.PropertyEditing.Mac</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\external\Xamarin.PropertyEditing\Xamarin.PropertyEditing\Xamarin.PropertyEditing.csproj">
+ <Project>{A0B6FE73-D046-4E1C-BA9D-F20683889C5A}</Project>
+ <Name>Xamarin.PropertyEditing</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
@@ -149,6 +157,18 @@
<Compile Include="MonoDevelop.DesignerSupport.Toolbox\MacToolboxWidgetFlowLayoutDelegate.cs" />
<Compile Include="MonoDevelop.DesignerSupport.Toolbox\Styles.cs" />
<Compile Include="MonoDevelop.DesignerSupport.Toolbox\Toolbox.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\MacPropertyGrid.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyPadObjectEditor.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyPadEditorProvider.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyProviderTypeInfo.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyDescriptorEventInfo.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\DescriptorPropertyInfo.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\EnumDescriptorPropertyInfo.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\StringStandardValuesPropertyInfo.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\FilePathPropertyInfo.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\DirectoryPathPropertyInfo.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\IPropertyPad.cs" />
+ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\FlagDescriptorPropertyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="MonoDevelop.DesignerSupport.addin.xml" />
@@ -188,6 +208,8 @@
<ItemGroup>
<Folder Include="MonoDevelop.DesignerSupport.Toolbox\Helpers\" />
<Folder Include="MonoDevelop.DesignerSupport.Toolbox\NativeViews\" />
+ <Folder Include="MonoDevelop.DesignerSupport\NativePropertyEditors\" />
+ <Folder Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs
index 10f6e33171..822dce6947 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs
@@ -43,7 +43,7 @@ namespace MonoDevelop.DesignerSupport
{
public class DesignerSupportService
{
- PropertyPad propertyPad = null;
+ IPropertyPad propertyPad = null;
ToolboxService toolboxService = null;
IPropertyProvider[] providers;
@@ -53,13 +53,13 @@ namespace MonoDevelop.DesignerSupport
#region PropertyPad
- public PropertyPad PropertyPad {
+ public IPropertyPad PropertyPad {
get {
return propertyPad;
}
}
- internal void SetPad (PropertyPad pad)
+ internal void SetPad (IPropertyPad pad)
{
propertyPad = pad;
@@ -67,26 +67,28 @@ namespace MonoDevelop.DesignerSupport
if (lastPadProvider != null) {
object[] provs = GetProvidersForObject (lastComponent, lastPadProvider.GetProvider ());
if (provs.Length > 0)
- propertyPad.PropertyGrid.SetCurrentObject (lastComponent, provs);
+ propertyPad.SetCurrentObject (lastComponent, provs);
else
propertyPad.BlankPad ();
-
- var customizer = lastPadProvider as IPropertyPadCustomizer;
- if (customizer != null)
- customizer.Customize (pad.PadWindow, pad.PropertyGrid);
- propertyPad.PropertyGrid.Changed += OnPropertyGridChanged;
+
+ if (lastPadProvider is IPropertyPadCustomizer customizer && pad is PropertyPad ppad) {
+ customizer.Customize (ppad.PadWindow, ppad.PropertyGrid);
+ }
+ propertyPad.PropertyGridChanged += OnPropertyGridChanged;
}
else if (lastCustomProvider != null) {
- try {
- var currentCustomWidget = lastCustomProvider.GetCustomPropertyWidget ();
- if (currentCustomWidget != null) {
- propertyPad.UseCustomWidget (currentCustomWidget);
- if (lastCustomProvider is IPropertyPadCustomizer customizer)
- customizer.Customize (pad.PadWindow, null);
+ if (propertyPad is PropertyPad ppad) {
+ try {
+ var currentCustomWidget = lastCustomProvider.GetCustomPropertyWidget ();
+ if (currentCustomWidget != null) {
+ ppad.UseCustomWidget (currentCustomWidget);
+ if (lastCustomProvider is IPropertyPadCustomizer customizer)
+ customizer.Customize (ppad.PadWindow, null);
+ }
+ } catch (Exception ex) {
+ LoggingService.LogInternalError ($"There was an error trying to GetCustomPropertyWidget from '{lastCustomProvider.GetType ()}' provider", ex);
+ ReSetPad ();
}
- } catch (Exception ex) {
- LoggingService.LogInternalError ($"There was an error trying to GetCustomPropertyWidget from '{lastCustomProvider.GetType ()}' provider", ex);
- ReSetPad ();
}
}
}
@@ -95,8 +97,8 @@ namespace MonoDevelop.DesignerSupport
void DisposePropertyPadProvider ()
{
if (lastPadProvider != null) {
- if (propertyPad != null && propertyPad.PropertyGrid != null)
- propertyPad.PropertyGrid.Changed -= OnPropertyGridChanged;
+ if (propertyPad != null)
+ propertyPad.PropertyGridChanged -= OnPropertyGridChanged;
lastPadProvider.OnEndEditing (lastComponent);
lastPadProvider = null;
lastComponent = null;
@@ -144,17 +146,19 @@ namespace MonoDevelop.DesignerSupport
object[] provs = GetProvidersForObject (comp, provider.GetProvider ());
if (provs.Length > 0) {
- propertyPad.PropertyGrid.SetCurrentObject (comp, provs);
- propertyPad.CommandRouteOrigin = commandRouteOrigin;
+ propertyPad.SetCurrentObject (comp, provs);
+
+ if (propertyPad is PropertyPad propPad) {
+ propPad.CommandRouteOrigin = commandRouteOrigin;
+ }
}
else
propertyPad.BlankPad ();
-
- var customizer = provider as IPropertyPadCustomizer;
- if (customizer != null)
- customizer.Customize (propertyPad.PadWindow, propertyPad.PropertyGrid);
-
- propertyPad.PropertyGrid.Changed += OnPropertyGridChanged;
+
+ if (provider is IPropertyPadCustomizer customizer && propertyPad is PropertyPad ppad)
+ customizer.Customize (ppad.PadWindow, ppad.PropertyGrid);
+
+ propertyPad.PropertyGridChanged += OnPropertyGridChanged;
}
else {
ReSetPad ();
@@ -178,17 +182,16 @@ namespace MonoDevelop.DesignerSupport
DisposeCustomPropertyPadProvider ();
lastCustomProvider = provider;
-
- if (propertyPad != null) {
+
+ if (propertyPad != null && propertyPad is PropertyPad ppad) {
try {
var customWidget = provider.GetCustomPropertyWidget ();
if (customWidget != null) {
- propertyPad.UseCustomWidget (customWidget);
- propertyPad.CommandRouteOrigin = commandRouteOrigin;
-
+ ppad.UseCustomWidget (customWidget);
+ ppad.CommandRouteOrigin = commandRouteOrigin;
var customizer = provider as IPropertyPadCustomizer;
if (customizer != null)
- customizer.Customize (propertyPad.PadWindow, null);
+ customizer.Customize (ppad.PadWindow, null);
} else {
propertyPad?.BlankPad ();
return;
@@ -225,9 +228,9 @@ namespace MonoDevelop.DesignerSupport
lastPadProvider.OnChanged (lastComponent);
}
- #endregion
+#endregion
- #region Toolbox
+#region Toolbox
public ToolboxService ToolboxService {
get{
@@ -240,7 +243,7 @@ namespace MonoDevelop.DesignerSupport
}
}
- #endregion
+#endregion
internal DesignerSupportService ()
{
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs
new file mode 100644
index 0000000000..18c610f946
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs
@@ -0,0 +1,16 @@
+
+using System;
+
+namespace MonoDevelop.DesignerSupport
+{
+ public interface IPropertyPad
+ {
+ bool IsGridEditing { get; }
+
+ event EventHandler PropertyGridChanged;
+
+ void SetCurrentObject (object lastComponent, object [] propertyProviders);
+ void BlankPad ();
+ void PopulateGrid (bool saveEditSession);
+ }
+}
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs
new file mode 100644
index 0000000000..de3512f570
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs
@@ -0,0 +1,164 @@
+
+/*
+ * PropertyPad.cs: The pad that holds the MD property grid. Can also
+ * hold custom grid widgets.
+ *
+ * Author:
+ * Jose Medrano <josmed@microsoft.com>
+ *
+ * Copyright (C) 2018 Microsoft, Corp
+ *
+ * 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.
+ */
+
+#if MAC
+
+using MonoDevelop.Ide.Gui;
+using MonoDevelop.Components.Commands;
+using System;
+using MonoDevelop.Components;
+using Xamarin.PropertyEditing;
+using Xamarin.PropertyEditing.Mac;
+using MonoDevelop.Components.Mac;
+using MonoDevelop.Ide;
+using MonoDevelop.Ide.Commands;
+using MonoDevelop.Components.Theming;
+using AppKit;
+using CoreGraphics;
+using Foundation;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class MacPropertyGrid : NSStackView, IPropertyGrid
+ {
+ MacPropertyEditorPanel propertyEditorPanel;
+
+ PropertyPadEditorProvider editorProvider;
+
+ NSScrollView scrollView;
+
+ public event EventHandler Focused;
+
+ public bool IsEditing => false;
+
+ public event EventHandler PropertyGridChanged;
+
+ public MacPropertyGrid ()
+ {
+ Orientation = NSUserInterfaceLayoutOrientation.Vertical;
+ Alignment = NSLayoutAttribute.Leading;
+ Spacing = 10;
+ Distribution = NSStackViewDistribution.Fill;
+
+ propertyEditorPanel = new MacPropertyEditorPanel ();
+
+ scrollView = new NSScrollView () {
+ HasVerticalScroller = true,
+ HasHorizontalScroller = false,
+ };
+ scrollView.WantsLayer = true;
+ scrollView.BackgroundColor = Styles.HeaderBackgroundColor;
+ scrollView.DocumentView = propertyEditorPanel;
+
+ AddArrangedSubview (scrollView);
+
+ propertyEditorPanel.Focused += PropertyEditorPanel_Focused;
+
+ //propertyEditorPanel.PropertiesChanged += PropertyEditorPanel_PropertiesChanged;
+ }
+
+ void Widget_Focused (object o, Gtk.FocusedArgs args)
+ {
+ propertyEditorPanel.BecomeFirstResponder ();
+ }
+
+ void PropertyEditorPanel_Focused (object sender, EventArgs e) => Focused?.Invoke (this, EventArgs.Empty);
+
+ public override void SetFrameSize (CGSize newSize)
+ {
+ scrollView.SetFrameSize (newSize);
+ base.SetFrameSize (newSize);
+ }
+
+ void PropertyEditorPanel_PropertiesChanged (object sender, EventArgs e) => PropertyGridChanged?.Invoke (this, e);
+
+ public void BlankPad ()
+ {
+ propertyEditorPanel.SelectedItems.Clear ();
+ currentSelectedObject = null;
+ }
+
+ public void OnPadContentShown ()
+ {
+ if (editorProvider == null) {
+ editorProvider = new PropertyPadEditorProvider ();
+ propertyEditorPanel.TargetPlatform = new TargetPlatform (editorProvider) {
+ AutoExpandGroups = new string [] { "Build", "Misc", "NuGet", "Reference" }
+ };
+ propertyEditorPanel.ArrangeMode = PropertyArrangeMode.Category;
+ }
+ }
+
+ Tuple<object, object []> currentSelectedObject;
+
+ public void SetCurrentObject (object lastComponent, object [] propertyProviders)
+ {
+ if (lastComponent != null) {
+ var selection = new Tuple<object, object []> (lastComponent, propertyProviders);
+ if (currentSelectedObject != selection) {
+ propertyEditorPanel.SelectedItems.Clear ();
+ propertyEditorPanel.SelectedItems.Add (new Tuple<object, object []> (lastComponent, propertyProviders));
+ currentSelectedObject = selection;
+ }
+ }
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (propertyEditorPanel != null) {
+ propertyEditorPanel.Focused -= PropertyEditorPanel_Focused;
+ }
+ base.Dispose (disposing);
+ }
+
+ public void Populate (bool saveEditSession)
+ {
+ //not implemented
+ }
+
+ public void SetToolbarProvider (Components.PropertyGrid.PropertyGrid.IToolbarProvider toolbarProvider)
+ {
+ //not implemented
+ }
+ }
+
+ class MacPropertyEditorPanel : PropertyEditorPanel
+ {
+ public EventHandler Focused;
+
+ public override bool BecomeFirstResponder ()
+ {
+ Focused?.Invoke (this, EventArgs.Empty);
+ return base.BecomeFirstResponder ();
+ }
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyDescriptorEventInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyDescriptorEventInfo.cs
new file mode 100644
index 0000000000..12c8609994
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyDescriptorEventInfo.cs
@@ -0,0 +1,66 @@
+//
+// PropertyPadObjectEditor.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using System;
+using System.Collections.Generic;
+using Xamarin.PropertyEditing;
+using System.Linq;
+using System.Reflection;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class PropertyDescriptorEventInfo
+ : IEventInfo
+ {
+ public PropertyDescriptorEventInfo (EventInfo info)
+ {
+ this.info = info ?? throw new ArgumentNullException (nameof (info));
+ }
+
+ public string Name => this.info.Name;
+
+ public IReadOnlyList<string> GetHandlers (object target)
+ {
+ //TODO:
+ if (target == null)
+ return Array.Empty<string> ();
+
+ Type targetType = target.GetType ();
+ FieldInfo field = targetType.GetField ($"Event{Name}", BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
+ Delegate d = field?.GetValue (target) as Delegate;
+ if (d == null)
+ return Array.Empty<string> ();
+
+ return d.GetInvocationList ().Select (i => i.Method.Name).ToList ();
+ }
+
+ private readonly EventInfo info;
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DescriptorPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DescriptorPropertyInfo.cs
new file mode 100644
index 0000000000..033470859b
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DescriptorPropertyInfo.cs
@@ -0,0 +1,155 @@
+//
+// DescriptorPropertyInfo.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using System.Linq;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xamarin.PropertyEditing;
+using Xamarin.PropertyEditing.Reflection;
+using System.Reflection;
+using System.ComponentModel;
+using System.Collections;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class DescriptorPropertyInfo
+ : IPropertyInfo, IEquatable<DescriptorPropertyInfo>
+ {
+ public PropertyDescriptor PropertyDescriptor { get; private set; }
+ public object PropertyProvider { get; private set; }
+ readonly ValueSources valueSources;
+ static readonly IAvailabilityConstraint [] EmptyConstraints = new IAvailabilityConstraint [0];
+ static readonly PropertyVariationOption [] EmptyVariationOptions = new PropertyVariationOption [0];
+
+ public DescriptorPropertyInfo (PropertyDescriptor propertyInfo, object propertyProvider, ValueSources valueSources)
+ {
+ this.PropertyDescriptor = propertyInfo;
+ this.PropertyProvider = propertyProvider;
+ this.valueSources = valueSources;
+ }
+
+ public string Name => PropertyDescriptor.DisplayName;
+
+ public string Description => PropertyDescriptor.Description;
+
+ public virtual Type Type => PropertyDescriptor.PropertyType;
+
+ public ITypeInfo RealType => ToTypeInfo (PropertyDescriptor, PropertyProvider, Type);
+
+ public string Category => PropertyDescriptor.Category;
+
+ public bool CanWrite => !PropertyDescriptor.IsReadOnly;
+
+ public ValueSources ValueSources => valueSources;
+
+ public IReadOnlyList<PropertyVariationOption> Variations => EmptyVariationOptions;
+
+ public IReadOnlyList<IAvailabilityConstraint> AvailabilityConstraints => EmptyConstraints;
+
+ public bool IsUncommon => false;
+
+ public bool Equals (DescriptorPropertyInfo other)
+ {
+ if (other is null)
+ return false;
+ if (ReferenceEquals (this, other))
+ return true;
+
+ return PropertyDescriptor.Equals (other.PropertyDescriptor);
+ }
+
+ public override bool Equals (object obj)
+ {
+ return obj is DescriptorPropertyInfo info && Equals (info);
+ }
+
+ public override int GetHashCode ()
+ {
+ return PropertyDescriptor.GetHashCode ();
+ }
+
+ public static Type GetCollectionItemType (Type colType)
+ {
+ foreach (var member in colType.GetDefaultMembers ()) {
+ var prop = member as PropertyInfo;
+ if (prop != null && prop.Name == "Item" && prop.PropertyType != typeof (object))
+ return prop.PropertyType;
+ }
+ return null;
+ }
+
+ public static ITypeInfo ToTypeInfo (PropertyDescriptor propertyDescriptor, object propertyProvider, Type type, bool isRelevant = true)
+ {
+ var asm = type.Assembly.GetName ().Name;
+ return new PropertyProviderTypeInfo (propertyDescriptor, propertyProvider, new AssemblyInfo (asm, isRelevant), type.Namespace, type.Name);
+ }
+
+ const string ErrorOnGetValueMessage = "Error in GetValueAsync<T> using property descriptor converter";
+ protected void LogGetValueAsyncError (Exception ex) => LoggingService.LogError (ErrorOnGetValueMessage, ex);
+
+ internal virtual Task<T> GetValueAsync<T> (object target)
+ {
+ object value = null;
+
+ try {
+ value = PropertyDescriptor.GetValue (PropertyProvider);
+ TypeConverter tc = PropertyDescriptor.Converter;
+ if (tc.CanConvertTo (typeof (T))) {
+ value = tc.ConvertTo (value, typeof (T));
+ }
+ return Task.FromResult ((T)value);
+ } catch (Exception ex) {
+ LogGetValueAsyncError (ex);
+ }
+
+ T converted = default;
+ try {
+ if (value != null && !(value is T)) {
+ if (typeof (T) == typeof (string)) {
+ value = value.ToString ();
+ } else {
+ value = Convert.ChangeType (value, typeof (T));
+ }
+ }
+ return Task.FromResult ((T)value);
+ } catch (Exception ex) {
+ LogGetValueAsyncError (ex);
+ }
+ return Task.FromResult (converted);
+ }
+
+ internal virtual void SetValue<T> (object target, T value)
+ {
+ PropertyDescriptor.SetValue (PropertyProvider, value);
+ }
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs
new file mode 100644
index 0000000000..6a070d80c1
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs
@@ -0,0 +1,71 @@
+//
+// DescriptorPropertyInfo.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using System;
+using System.Threading.Tasks;
+using Xamarin.PropertyEditing;
+using System.ComponentModel;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class DirectoryPathPropertyInfo
+ : DescriptorPropertyInfo, IEquatable<DescriptorPropertyInfo>
+ {
+ public DirectoryPathPropertyInfo (PropertyDescriptor propertyInfo, object propertyProvider, ValueSources valueSources) : base (propertyInfo, propertyProvider, valueSources)
+ {
+ }
+
+ public override Type Type => typeof (DirectoryPath);
+
+ internal override void SetValue<T> (object target, T value)
+ {
+ if (value is DirectoryPath directoryPath) {
+ PropertyDescriptor.SetValue (PropertyProvider, new MonoDevelop.Core.FilePath (directoryPath.Source));
+ } else {
+ throw new Exception (string.Format ("Value: {0} of type {1} is not a DirectoryPath", value, value.GetType ()));
+ }
+ }
+
+ internal override Task<T> GetValueAsync<T> (object target)
+ {
+ try {
+ if (target is Core.FilePath directoryPath) {
+ T result = (T)(object)new DirectoryPath (directoryPath.FullPath);
+ return Task.FromResult (result);
+ }
+ LoggingService.LogWarning (string.Format ("Value: {0} of type {1} is not a DirectoryPath", target, target.GetType ()));
+ } catch (Exception e) {
+ LogGetValueAsyncError (e);
+ }
+ return base.GetValueAsync<T> (target);
+ }
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/EnumDescriptorPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/EnumDescriptorPropertyInfo.cs
new file mode 100644
index 0000000000..dc5a6c03f3
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/EnumDescriptorPropertyInfo.cs
@@ -0,0 +1,111 @@
+//
+// EnumDescriptorPropertyInfo.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using System;
+using Xamarin.PropertyEditing;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System.Collections;
+using System.Threading.Tasks;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class EnumDescriptorPropertyInfo
+ : DescriptorPropertyInfo, IHavePredefinedValues<string> //, IValidator<IReadOnlyList<string>>, ICoerce<IReadOnlyList<string>>
+ {
+ Hashtable names = new Hashtable ();
+ Array values;
+ public EnumDescriptorPropertyInfo (PropertyDescriptor propertyDescriptor, object propertyProvider, ValueSources valueSources)
+ : base (propertyDescriptor, propertyProvider, valueSources)
+ {
+ values = Enum.GetValues (PropertyDescriptor.PropertyType);
+ var fields = PropertyDescriptor.PropertyType.GetFields ();
+
+ names = new Hashtable ();
+ foreach (System.Reflection.FieldInfo f in fields) {
+ var att = (DescriptionAttribute)Attribute.GetCustomAttribute (f, typeof (DescriptionAttribute));
+ if (att != null)
+ names [f.Name] = att.Description;
+ else
+ names [f.Name] = f.Name;
+ }
+
+ for (int i = 0; i < values.Length; i++) {
+ //name
+ var value = values.GetValue (i);
+ string str = PropertyDescriptor.Converter.ConvertToString (value);
+ if (names.Contains (str))
+ str = (string)names [str];
+ predefinedValues.Add (str, i.ToString ());
+ }
+ }
+
+ internal override void SetValue<T> (object target, T value)
+ {
+ var tc = PropertyDescriptor.Converter;
+ if (tc.CanConvertFrom (typeof (T))) {
+ if (int.TryParse ((string)(object)value, out var index)) {
+ PropertyDescriptor.SetValue (PropertyProvider, values.GetValue (index));
+ } else {
+ throw new Exception (string.Format ("Error in SetValue<T> parsing {0} as integer in {1} (enum descriptor)", value, PropertyDescriptor.DisplayName));
+ }
+ }
+ }
+
+ internal override Task<T> GetValueAsync<T> (object target)
+ {
+ //we need set the index of the selected item
+ T result = default;
+ try {
+ TypeConverter tc = PropertyDescriptor.Converter;
+ object cob = PropertyDescriptor.GetValue (PropertyProvider);
+ var index = Array.IndexOf (values, cob);
+ if (index > -1) {
+ result = (T)(object) index.ToString ();
+ } else {
+ LoggingService.LogError ("Error in GetValueAsync<T> parsing {0} as integer in {1} (enum descriptor)", index, PropertyDescriptor.DisplayName);
+ }
+ } catch (Exception ex) {
+ LogGetValueAsyncError (ex);
+ }
+ return Task.FromResult (result);
+ }
+
+ public bool IsConstrainedToPredefined => false;
+
+ public bool IsValueCombinable {
+ get;
+ }
+
+ readonly protected Dictionary<string, string> predefinedValues = new Dictionary<string, string> ();
+ public IReadOnlyDictionary<string, string> PredefinedValues => predefinedValues;
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs
new file mode 100644
index 0000000000..563c5eee6b
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs
@@ -0,0 +1,66 @@
+//
+// DescriptorPropertyInfo.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using System;
+using System.Threading.Tasks;
+using Xamarin.PropertyEditing;
+using System.ComponentModel;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class FilePathPropertyInfo
+ : DescriptorPropertyInfo, IEquatable<DescriptorPropertyInfo>
+ {
+ public FilePathPropertyInfo (PropertyDescriptor propertyInfo, object propertyProvider, ValueSources valueSources) : base (propertyInfo, propertyProvider, valueSources)
+ {
+ }
+
+ public override Type Type => typeof (FilePath);
+
+ internal override void SetValue<T> (object target, T value)
+ {
+ if (value is FilePath filePath) {
+ PropertyDescriptor.SetValue (PropertyProvider, new MonoDevelop.Core.FilePath (filePath.Source));
+ } else {
+ throw new Exception (string.Format ("Value: {0} of type {1} is not a DirectoryPath", value, value.GetType ()));
+ }
+ }
+
+ internal override Task<T> GetValueAsync<T> (object target)
+ {
+ if (target is Core.FilePath directoryPath) {
+ T result = (T)(object)new FilePath (directoryPath.FullPath);
+ return Task.FromResult (result);
+ }
+ Core.LoggingService.LogWarning ("Value: {0} of type {1} is not a DirectoryPath", target, target.GetType ());
+ return base.GetValueAsync<T> (target);
+ }
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FlagDescriptorPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FlagDescriptorPropertyInfo.cs
new file mode 100644
index 0000000000..d485704ca8
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FlagDescriptorPropertyInfo.cs
@@ -0,0 +1,91 @@
+//
+// FlagDescriptorPropertyInfo.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using Xamarin.PropertyEditing;
+using System.ComponentModel;
+using System.Threading.Tasks;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class FlagDescriptorPropertyInfo
+ : DescriptorPropertyInfo, IHavePredefinedValues<string>
+ {
+ public FlagDescriptorPropertyInfo (PropertyDescriptor propertyDescriptor, object propertyProvider, ValueSources valueSources) : base (propertyDescriptor, propertyProvider, valueSources)
+ {
+ IsValueCombinable = true;
+ foreach (object value in System.Enum.GetValues (propertyDescriptor.PropertyType)) {
+ ulong uintVal = Convert.ToUInt64 (value);
+ predefinedValues.Add (value.ToString (), uintVal.ToString ());
+ }
+ }
+
+ internal override void SetValue<T> (object target, T value)
+ {
+ var selectedValues = (System.String []) (object)value;
+ ulong result = default;
+ foreach (var selectedValue in selectedValues) {
+ result += Convert.ToUInt64 (selectedValue);
+ }
+ PropertyDescriptor.SetValue (PropertyProvider, Enum.ToObject (PropertyDescriptor.PropertyType, result));
+ }
+
+ internal override Task<T> GetValueAsync<T> (object target)
+ {
+ //we need set the index of the selected item
+ try {
+ var myValue = (Enum)target;
+ var result = new List<string> ();
+ foreach (Enum item in Enum.GetValues (target.GetType ()))
+ {
+ if (myValue.HasFlag (item)) {
+ ulong uintVal = Convert.ToUInt64 (item);
+ result.Add (uintVal.ToString ());
+ }
+ }
+ return Task.FromResult<T> ((T)(object)result);
+ } catch (Exception ex) {
+ LogGetValueAsyncError (ex);
+ }
+ return Task.FromResult <T> (default);
+ }
+
+ public bool IsConstrainedToPredefined => true;
+
+ public bool IsValueCombinable {
+ get;
+ }
+
+ readonly protected Dictionary<string, string> predefinedValues = new Dictionary<string, string> ();
+ public IReadOnlyDictionary<string, string> PredefinedValues => predefinedValues;
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/StringStandardValuesPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/StringStandardValuesPropertyInfo.cs
new file mode 100644
index 0000000000..6f1eb5d724
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/StringStandardValuesPropertyInfo.cs
@@ -0,0 +1,57 @@
+//
+// StringStandardValuesPropertyInfo.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using Xamarin.PropertyEditing;
+using System.ComponentModel;
+using System.Collections.Generic;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class StringStandardValuesPropertyInfo
+ : DescriptorPropertyInfo, IHavePredefinedValues<string>
+ {
+ public StringStandardValuesPropertyInfo (PropertyDescriptor propertyDescriptor, object propertyProvider, ValueSources valueSources) : base (propertyDescriptor, propertyProvider, valueSources)
+ {
+ foreach (object stdValue in PropertyDescriptor.Converter.GetStandardValues ()) {
+ var value = PropertyDescriptor.Converter.ConvertToString (stdValue);
+ predefinedValues.Add (value, value);
+ }
+ }
+
+ public bool IsConstrainedToPredefined => false;
+
+ public bool IsValueCombinable {
+ get;
+ }
+
+ protected Dictionary<string, string> predefinedValues = new Dictionary<string, string> ();
+ public IReadOnlyDictionary<string, string> PredefinedValues => predefinedValues;
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs
new file mode 100644
index 0000000000..1d74baaf33
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs
@@ -0,0 +1,80 @@
+//
+// PropertyPadEditorProvider.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using System.Linq;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xamarin.PropertyEditing;
+using Xamarin.PropertyEditing.Common;
+using Xamarin.PropertyEditing.Reflection;
+using System.Reflection;
+using System.ComponentModel;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class PropertyPadEditorProvider
+ : IEditorProvider
+ {
+ Tuple<object, object[]> currentObject;
+ IObjectEditor currentEditor;
+
+ public IReadOnlyDictionary<Type, ITypeInfo> KnownTypes {
+ get;
+ } = new Dictionary<Type, ITypeInfo> ();
+
+ public Task<IObjectEditor> GetObjectEditorAsync (object item)
+ {
+ if (item is Tuple<object, object []> tuple) {
+ this.currentObject = tuple;
+ this.currentEditor = new PropertyPadObjectEditor (tuple); ;
+ return Task.FromResult (currentEditor);
+ }
+ return Task.FromResult<IObjectEditor> (null);
+ }
+
+ public Task<object> CreateObjectAsync (ITypeInfo type)
+ {
+ var realType = Type.GetType ($"{type.NameSpace}.{type.Name}, {type.Assembly.Name}");
+ if (realType == null)
+ return Task.FromResult<object> (null);
+ return Task.FromResult (Activator.CreateInstance (realType));
+ }
+
+ public Task<IReadOnlyCollection<IPropertyInfo>> GetPropertiesForTypeAsync (ITypeInfo type)
+ => Task.FromResult<IReadOnlyCollection<IPropertyInfo>> (new List<IPropertyInfo> ());
+
+ public Task<AssignableTypesResult> GetAssignableTypesAsync (ITypeInfo type, bool childTypes)
+ => Task.FromResult (new AssignableTypesResult (new List<ITypeInfo> ()));
+
+ public Task<IReadOnlyList<object>> GetChildrenAsync (object item)
+ => Task.FromResult<IReadOnlyList<object>> (Array.Empty<object> ());
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs
new file mode 100644
index 0000000000..40fa6dc49a
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs
@@ -0,0 +1,235 @@
+//
+// PropertyPadObjectEditor.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xamarin.PropertyEditing;
+using Xamarin.PropertyEditing.Reflection;
+using System.Linq;
+using System.ComponentModel;
+using System.Collections;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class PropertyPadObjectEditor
+ : IObjectEditor, INameableObject, IObjectEventEditor
+ {
+ private readonly object target;
+ public string Name {
+ get;
+ private set;
+ }
+
+ private readonly List<IPropertyInfo> properties = new List<IPropertyInfo> ();
+ private static readonly IObjectEditor [] EmptyDirectChildren = new IObjectEditor [0];
+ private readonly List<PropertyDescriptorEventInfo> events = new List<PropertyDescriptorEventInfo> ();
+
+ public object Target => this.target;
+
+ public ITypeInfo TargetType => ToTypeInfo (Target.GetType ());
+
+ public static ITypeInfo ToTypeInfo (Type type, bool isRelevant = true)
+ {
+ var asm = type.Assembly.GetName ().Name;
+ return new TypeInfo (new AssemblyInfo (asm, isRelevant), type.Namespace, type.Name);
+ }
+
+ public IReadOnlyCollection<IPropertyInfo> Properties => this.properties;
+
+ public IReadOnlyDictionary<IPropertyInfo, KnownProperty> KnownProperties => null;
+
+ public IObjectEditor Parent => throw new NotImplementedException ();
+
+ public IReadOnlyList<IObjectEditor> DirectChildren => EmptyDirectChildren;
+
+ public IReadOnlyCollection<IEventInfo> Events => this.events;
+
+ public event EventHandler<EditorPropertyChangedEventArgs> PropertyChanged;
+
+ public PropertyPadObjectEditor (Tuple<object, object []> target)
+ {
+ this.target = target.Item1;
+ foreach (object propertyProvider in target.Item2) {
+ var props = GetProperties (propertyProvider, null);
+
+ for (int i = 0; i < props.Count; i++) {
+ var prop = props [i] as PropertyDescriptor;
+ if (prop.IsBrowsable) {
+ properties.Add (CreatePropertyInfo (prop, propertyProvider));
+ }
+ }
+ }
+ }
+
+ bool HasStandardValues (PropertyDescriptor propertyDescriptor)
+ {
+ if (propertyDescriptor.Converter.GetStandardValuesSupported ()) {
+ if (!propertyDescriptor.Converter.GetStandardValuesExclusive () && propertyDescriptor.Converter.CanConvertFrom (typeof (string))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ PropertyDescriptor GetPropertyDescriptor (PropertyDescriptorCollection collection, string name)
+ {
+ for (int i = 0; i < collection.Count; i++) {
+ if (collection[i].Name == name) {
+ return collection [i];
+ }
+ }
+ return null;
+ }
+
+ protected IPropertyInfo CreatePropertyInfo (PropertyDescriptor propertyDescriptor, object PropertyProvider)
+ {
+ var valueSources = ValueSources.Local | ValueSources.Default;
+ if (propertyDescriptor.PropertyType.IsEnum) {
+ if (propertyDescriptor.PropertyType.IsDefined (typeof (FlagsAttribute), true))
+ return new FlagDescriptorPropertyInfo (propertyDescriptor, PropertyProvider, valueSources);
+ return new EnumDescriptorPropertyInfo (propertyDescriptor, PropertyProvider, valueSources);
+ }
+
+ if (propertyDescriptor.PropertyType.IsAssignableFrom (typeof (Core.FilePath))) {
+ var isDirectoryPropertyDescriptor = GetPropertyDescriptor (propertyDescriptor.GetChildProperties (), nameof (Core.FilePath.IsDirectory));
+ if (isDirectoryPropertyDescriptor != null && (bool)isDirectoryPropertyDescriptor.GetValue (target)) {
+ return new DirectoryPathPropertyInfo (propertyDescriptor, PropertyProvider, valueSources);
+ }
+ return new FilePathPropertyInfo (propertyDescriptor, PropertyProvider, valueSources);
+ }
+
+ if (HasStandardValues (propertyDescriptor)) {
+ return new StringStandardValuesPropertyInfo (propertyDescriptor, PropertyProvider, valueSources);
+ }
+
+ return new DescriptorPropertyInfo (propertyDescriptor, PropertyProvider, valueSources);
+ }
+
+ public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes)
+ {
+ if (component == null)
+ return new PropertyDescriptorCollection (new PropertyDescriptor [] { });
+ return TypeDescriptor.GetProperties (component);
+ }
+
+ #region NOT SUPORTED
+
+ public Task AttachHandlerAsync (IEventInfo ev, string handlerName)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Task DetachHandlerAsync (IEventInfo ev, string handlerName)
+ {
+ throw new NotImplementedException ();
+ }
+
+ #endregion
+
+ public async Task<AssignableTypesResult> GetAssignableTypesAsync (IPropertyInfo property, bool childTypes)
+ {
+ return new AssignableTypesResult (Array.Empty<ITypeInfo> ());
+ }
+
+ public Task<IReadOnlyList<string>> GetHandlersAsync (IEventInfo ev)
+ {
+ if (ev == null)
+ throw new ArgumentNullException (nameof (ev));
+
+ if (!(ev is Xamarin.PropertyEditing.Reflection.ReflectionEventInfo info))
+ throw new ArgumentException ();
+
+ return Task.FromResult (info.GetHandlers (this.target));
+ }
+
+ public Task<string> GetNameAsync ()
+ {
+ return Task.FromResult (Name);
+ }
+
+ public Task<IReadOnlyCollection<PropertyVariation>> GetPropertyVariantsAsync (IPropertyInfo property)
+ {
+ return Task.FromResult<IReadOnlyCollection<PropertyVariation>> (new PropertyVariation [0]);
+ }
+
+ public async Task<ValueInfo<T>> GetValueAsync<T> (IPropertyInfo property, PropertyVariation variations = null)
+ {
+ if (property == null)
+ throw new ArgumentNullException (nameof (property));
+
+ if (!(property is DescriptorPropertyInfo info))
+ throw new ArgumentException ();
+
+ T value = await info.GetValueAsync<T> (this.target);
+
+ return new ValueInfo<T> {
+ Value = value,
+ Source = ValueSource.Local,
+ //ValueDescriptor = valueInfoString.ValueDescriptor,
+ //CustomExpression = valueString
+ };
+ }
+
+ public Task RemovePropertyVariantAsync (IPropertyInfo property, PropertyVariation variant)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task SetNameAsync (string name)
+ {
+ Name = name;
+ return Task.FromResult (true);
+ }
+
+ public Task SetValueAsync<T> (IPropertyInfo propertyInfo, ValueInfo<T> valueInfo, PropertyVariation variations = null)
+ {
+ if (propertyInfo == null)
+ throw new ArgumentNullException (nameof (propertyInfo));
+
+ if (propertyInfo is DescriptorPropertyInfo info && info.CanWrite) {
+ try {
+ info.SetValue (this.target, valueInfo.Value);
+ } catch (Exception ex) {
+ LoggingService.LogError ("Error setting the value", ex);
+ }
+
+ OnPropertyChanged (info);
+ }
+ return Task.CompletedTask;
+ }
+
+ protected virtual void OnPropertyChanged (IPropertyInfo property)
+ {
+ PropertyChanged?.Invoke (this, new EditorPropertyChangedEventArgs (property));
+ }
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyProviderTypeInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyProviderTypeInfo.cs
new file mode 100644
index 0000000000..2ac8c97afe
--- /dev/null
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyProviderTypeInfo.cs
@@ -0,0 +1,47 @@
+//
+// DescriptorPropertyInfo.cs
+//
+// Author:
+// jmedrano <josmed@microsoft.com>
+//
+// Copyright (c) 2018
+//
+// 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.
+
+#if MAC
+
+using Xamarin.PropertyEditing;
+using System.ComponentModel;
+
+namespace MonoDevelop.DesignerSupport
+{
+ class PropertyProviderTypeInfo : TypeInfo
+ {
+ public object PropertyProvider { get; }
+ public PropertyDescriptor PropertyDescriptor { get; }
+
+ public PropertyProviderTypeInfo (PropertyDescriptor propertyDescriptor, object propertyProvider, IAssemblyInfo assembly, string nameSpace, string name) : base (assembly, nameSpace, name)
+ {
+ PropertyDescriptor = propertyDescriptor;
+ PropertyProvider = propertyProvider;
+ }
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs
index fb18f70238..8631e439d1 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs
@@ -30,11 +30,8 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
-
using MonoDevelop.Ide.Gui;
-using MonoDevelop.DesignerSupport;
using pg = MonoDevelop.Components.PropertyGrid;
using MonoDevelop.Components.Docking;
using System.Collections.Generic;
@@ -42,34 +39,84 @@ using MonoDevelop.Components.Commands;
using MonoDevelop.Ide;
using MonoDevelop.Ide.Commands;
using MonoDevelop.Components;
+using System;
+using Gtk;
+using MonoDevelop.Core.FeatureConfiguration;
namespace MonoDevelop.DesignerSupport
{
-
- public class PropertyPad : PadContent, ICommandDelegator
+ public class PropertyPad : PadContent, ICommandDelegator, IPropertyPad
{
+ public event EventHandler PropertyGridChanged;
+
+ readonly bool isNative;
+ readonly IPropertyGrid propertyGrid;
+#if MAC
+ MacPropertyGrid nativeGrid;
+ Gtk.Widget gtkWidget;
+#endif
pg.PropertyGrid grid;
+
InvisibleFrame frame;
bool customWidget;
IPadWindow container;
DockToolbarProvider toolbarProvider = new DockToolbarProvider ();
internal object CommandRouteOrigin { get; set; }
-
+
+
public PropertyPad ()
{
- grid = new pg.PropertyGrid ();
frame = new InvisibleFrame ();
- frame.Add (grid);
-
+
+#if MAC
+ isNative = FeatureSwitchService.IsFeatureEnabled ("NativePropertyPanel") ?? false;
+
+ if (isNative) {
+
+ nativeGrid = new MacPropertyGrid ();
+ propertyGrid = nativeGrid;
+
+ gtkWidget = Components.Mac.GtkMacInterop.NSViewToGtkWidget (nativeGrid);
+ gtkWidget.CanFocus = true;
+ gtkWidget.Sensitive = true;
+ gtkWidget.Focused += Widget_Focused;
+
+ nativeGrid.Focused += PropertyGrid_Focused;
+ frame.Add (gtkWidget);
+ } else {
+#endif
+ grid = new pg.PropertyGrid ();
+ propertyGrid = grid;
+ grid.Changed += Grid_Changed;
+ frame.Add (grid);
+#if MAC
+ }
+#endif
frame.ShowAll ();
}
-
+
+ void Grid_Changed (object sender, EventArgs e)
+ {
+ PropertyGridChanged?.Invoke (this, e);
+ }
+#if MAC
+ void Widget_Focused (object o, Gtk.FocusedArgs args)
+ {
+ nativeGrid.BecomeFirstResponder ();
+ }
+#endif
protected override void Initialize (IPadWindow container)
{
base.Initialize (container);
toolbarProvider.Attach (container.GetToolbar (DockPositionType.Top));
- grid.SetToolbarProvider (toolbarProvider);
+
+ propertyGrid.SetToolbarProvider (toolbarProvider);
+
+ //native cocoa needs content shown to initialize stuff
+ if (isNative) {
+ container.PadContentShown += Window_PadContentShown;
+ }
this.container = container;
DesignerSupport.Service.SetPad (this);
}
@@ -78,7 +125,7 @@ namespace MonoDevelop.DesignerSupport
get { return container; }
}
- #region AbstractPadContent implementations
+#region AbstractPadContent implementations
public override Control Control {
get { return frame; }
@@ -86,13 +133,25 @@ namespace MonoDevelop.DesignerSupport
public override void Dispose()
{
+#if MAC
+ if (isNative) {
+ container.PadContentShown -= Window_PadContentShown;
+ nativeGrid.Focused -= PropertyGrid_Focused;
+ gtkWidget.Focused -= Widget_Focused;
+ } else {
+#endif
+ grid.Changed -= Grid_Changed;
+#if MAC
+ }
+#endif
+ propertyGrid.Dispose ();
DesignerSupport.Service.SetPad (null);
base.Dispose ();
}
- #endregion
+#endregion
- #region ICommandDelegatorRouter implementation
+#region ICommandDelegatorRouter implementation
object ICommandDelegator.GetDelegatedCommandTarget ()
{
@@ -105,28 +164,64 @@ namespace MonoDevelop.DesignerSupport
return null;
}
- #endregion
-
- //Grid consumers must call this when they lose focus!
+#endregion
+
+ public bool IsGridEditing {
+ get {
+ AttachToolbarIfCustomWidget ();
+ return propertyGrid.IsEditing;
+ }
+ }
+
+ //HACK: Mocked gtk property grid to satisfy for customizer.Customize call
+ readonly static pg.PropertyGrid pGrid = new pg.PropertyGrid ();
+ internal pg.PropertyGrid PropertyGrid {
+ get {
+ AttachToolbarIfCustomWidget ();
+ return isNative ? pGrid : grid;
+ }
+ }
+
public void BlankPad ()
{
- PropertyGrid.CurrentObject = null;
+ if (isNative) {
+ AttachToolbarIfCustomWidget ();
+ }
+ propertyGrid.BlankPad ();
CommandRouteOrigin = null;
}
-
- internal pg.PropertyGrid PropertyGrid {
- get {
- if (customWidget) {
- customWidget = false;
- frame.Remove (frame.Child);
+
+ void Window_PadContentShown (object sender, EventArgs e)
+ {
+ propertyGrid.OnPadContentShown ();
+ }
+#if MAC
+ void PropertyGrid_Focused (object sender, EventArgs e)
+ {
+ if (!gtkWidget.HasFocus) {
+ gtkWidget.HasFocus = true;
+ }
+ }
+#endif
+ void AttachToolbarIfCustomWidget ()
+ {
+ if (customWidget) {
+ customWidget = false;
+ frame.Remove (frame.Child);
+
+#if MAC
+ if (isNative) {
+ frame.Add (gtkWidget);
+ } else {
+#endif
frame.Add (grid);
- toolbarProvider.Attach (container.GetToolbar (DockPositionType.Top));
+#if MAC
}
-
- return grid;
+#endif
+ toolbarProvider.Attach (container.GetToolbar (DockPositionType.Top));
}
}
-
+
internal void UseCustomWidget (Gtk.Widget widget)
{
toolbarProvider.Attach (null);
@@ -145,8 +240,19 @@ namespace MonoDevelop.DesignerSupport
toolbar.Remove (w);
}
}
+
+ public void SetCurrentObject (object lastComponent, object [] propertyProviders)
+ {
+ AttachToolbarIfCustomWidget ();
+ propertyGrid.SetCurrentObject (lastComponent, propertyProviders);
+ }
+
+ public void PopulateGrid (bool saveEditSession)
+ {
+ propertyGrid.Populate (saveEditSession);
+ }
}
-
+
class DockToolbarProvider: pg.PropertyGrid.IToolbarProvider
{
DockItemToolbar tb;
@@ -171,7 +277,7 @@ namespace MonoDevelop.DesignerSupport
}
}
- #region IToolbarProvider implementation
+#region IToolbarProvider implementation
public void Insert (Gtk.Widget w, int pos)
{
if (tb != null)
@@ -213,7 +319,7 @@ namespace MonoDevelop.DesignerSupport
}
}
- #endregion
+#endregion
}
class InvisibleFrame : Gtk.Alignment
@@ -232,4 +338,5 @@ namespace MonoDevelop.DesignerSupport
return old;
}
}
+
}
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPadVisitor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPadVisitor.cs
index 27d76ec90f..44ceb4acf5 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPadVisitor.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPadVisitor.cs
@@ -88,7 +88,7 @@ namespace MonoDevelop.DesignerSupport
found = true;
return true;
}
- if (ob is PropertyPad) {
+ if (ob is IPropertyPad) {
// Don't change the property grid selection when the focus is inside the property grid itself
found = true;
return true;
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs
index b69333c078..0a9c270f1b 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs
@@ -32,6 +32,7 @@ using System;
using MonoDevelop.Ide.Gui;
using MonoDevelop.Components;
using Xwt;
+using Gtk;
#if MAC
using MonoDevelop.Components.Mac;
#endif
@@ -44,73 +45,108 @@ namespace MonoDevelop.DesignerSupport
#if MAC
Toolbox.MacToolbox toolbox;
+ IPadWindow window;
#endif
- protected override void Initialize (IPadWindow container)
+ protected override void Initialize (IPadWindow window)
{
- base.Initialize (container);
+ base.Initialize (window);
#if MAC
- toolbox = new Toolbox.MacToolbox (DesignerSupport.Service.ToolboxService, container);
+ this.window = window;
+ toolbox = new Toolbox.MacToolbox (DesignerSupport.Service.ToolboxService, window);
widget = GtkMacInterop.NSViewToGtkWidget (toolbox);
widget.CanFocus = true;
widget.Sensitive = true;
widget.KeyPressEvent += toolbox.OnKeyPressed;
widget.KeyReleaseEvent += toolbox.KeyReleased;
- widget.DragBegin += (o, args) => {
- if (!isDragging) {
- DesignerSupport.Service.ToolboxService.DragSelectedItem (widget, args.Context);
- isDragging = true;
- }
- };
+ widget.DragBegin += Widget_DragBegin;
+ widget.DragEnd += Widget_DragEnd;
+ widget.Focused += Widget_Focused;
- widget.DragEnd += (o, args) => {
- isDragging = false;
- };
+ this.window.PadContentShown += Container_PadContentShown;
+ this.window.PadContentHidden += Container_PadContentHidden;
- widget.Focused += (s, e) => {
- toolbox.FocusSelectedView ();
- };
+ toolbox.ContentFocused += Toolbox_ContentFocused;
+ toolbox.DragSourceSet += Toolbox_DragSourceSet;
+ toolbox.DragBegin += Toolbox_DragBegin;
- toolbox.ContentFocused += (s, e) => {
- if (!widget.HasFocus) {
- widget.HasFocus = true;
- toolbox.FocusSelectedView ();
- }
- };
- toolbox.DragSourceSet += (s, e) => {
- targets = new Gtk.TargetList ();
- targets.AddTable (e);
- };
- toolbox.DragBegin += (object sender, EventArgs e) => {
- var selectedNode = toolbox.SelectedNode;
- if (!isDragging && selectedNode != null) {
+ widget.ShowAll ();
+#else
+ widget = new Toolbox.Toolbox (DesignerSupport.Service.ToolboxService, window);
+#endif
+ }
- DesignerSupport.Service.ToolboxService.SelectItem (selectedNode);
+#if MAC
- Gtk.Drag.SourceUnset (widget);
+ void Container_PadContentShown (object sender, EventArgs args) => toolbox.Hidden = false;
+ void Container_PadContentHidden (object sender, EventArgs args) => toolbox.Hidden = true;
- // Gtk.Application.CurrentEvent and other copied gdk_events seem to have a problem
- // when used as they use gdk_event_copy which seems to crash on de-allocating the private slice.
- IntPtr currentEvent = GtkWorkarounds.GetCurrentEventHandle ();
- Gtk.Drag.Begin (widget, targets, Gdk.DragAction.Copy | Gdk.DragAction.Move, 1, new Gdk.Event (currentEvent, false));
+ private void Widget_DragEnd (object o, DragEndArgs args)
+ {
+ isDragging = false;
+ }
- // gtk_drag_begin does not store the event, so we're okay
- GtkWorkarounds.FreeEvent (currentEvent);
+ void Widget_Focused (object sender, EventArgs args)
+ {
+ toolbox.FocusSelectedView();
+ }
- }
- };
+ void Widget_DragBegin (object sender, DragBeginArgs args)
+ {
+ if (!isDragging) {
+ DesignerSupport.Service.ToolboxService.DragSelectedItem (widget, args.Context);
+ isDragging = true;
+ }
+ }
- widget.ShowAll ();
-#else
- widget = new Toolbox.Toolbox (DesignerSupport.Service.ToolboxService, container);
-#endif
+ void Toolbox_DragSourceSet (object sender, Gtk.TargetEntry [] e)
+ {
+ targets = new Gtk.TargetList ();
+ targets.AddTable (e);
}
-#if MAC
+
+ void Toolbox_ContentFocused (object sender, EventArgs args)
+ {
+ if (!widget.HasFocus) {
+ widget.HasFocus = true;
+ toolbox.FocusSelectedView ();
+ }
+ }
+
+ void Toolbox_DragBegin (object sender, EventArgs args)
+ {
+ var selectedNode = toolbox.SelectedNode;
+ if (!isDragging && selectedNode != null) {
+
+ DesignerSupport.Service.ToolboxService.SelectItem (selectedNode);
+
+ Gtk.Drag.SourceUnset (widget);
+
+ // Gtk.Application.CurrentEvent and other copied gdk_events seem to have a problem
+ // when used as they use gdk_event_copy which seems to crash on de-allocating the private slice.
+ IntPtr currentEvent = GtkWorkarounds.GetCurrentEventHandle ();
+ Gtk.Drag.Begin (widget, targets, Gdk.DragAction.Copy | Gdk.DragAction.Move, 1, new Gdk.Event (currentEvent, false));
+
+ // gtk_drag_begin does not store the event, so we're okay
+ GtkWorkarounds.FreeEvent (currentEvent);
+ }
+ }
+
Gtk.TargetList targets = new Gtk.TargetList ();
- bool isDragging = false;
+ bool isDragging;
+
public override void Dispose ()
{
+ if (window != null) {
+ window.PadContentShown -= Container_PadContentShown;
+ window.PadContentHidden -= Container_PadContentHidden;
+ window = null;
+ }
+
if (widget != null) {
+ widget.DragBegin -= Widget_DragBegin;
+ widget.DragEnd -= Widget_DragEnd;
+ widget.Focused -= Widget_Focused;
widget.KeyPressEvent -= toolbox.OnKeyPressed;
widget.KeyReleaseEvent -= toolbox.KeyReleased;
widget.Destroy ();
@@ -118,6 +154,9 @@ namespace MonoDevelop.DesignerSupport
widget = null;
}
if (toolbox != null) {
+ toolbox.ContentFocused -= Toolbox_ContentFocused;
+ toolbox.DragBegin -= Toolbox_DragBegin;
+ toolbox.DragSourceSet -= Toolbox_DragSourceSet;
toolbox.Dispose ();
toolbox = null;
}
diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Templating/DotNetCoreProjectTemplateStringTagProvider.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Templating/DotNetCoreProjectTemplateStringTagProvider.cs
index 182ea1a873..21f55b3f6d 100644
--- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Templating/DotNetCoreProjectTemplateStringTagProvider.cs
+++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Templating/DotNetCoreProjectTemplateStringTagProvider.cs
@@ -56,13 +56,11 @@ namespace MonoDevelop.DotNetCore.Templating
$"DotNetCoreSdk.{SupportedSDK [i]}.Templates.Web.ProjectTemplates.nupkg",
GettextCatalog.GetString (string.Format (".NET Core SDK {0} Web Project Templates NuGet package path", SupportedSDK[i]))
);
-
- if (i > 0 ) { //2.2 and before
- yield return new StringTagDescription (
- $"DotNetCoreSdk.{SupportedSDK [i]}.Templates.NUnit3.DotNetNew.Template.nupkg",
- GettextCatalog.GetString (string.Format (".NET Core SDK {0} NUnit Project Templates NuGet package path", SupportedSDK [i]))
- );
- }
+
+ yield return new StringTagDescription (
+ $"DotNetCoreSdk.{SupportedSDK [i]}.Templates.NUnit3.DotNetNew.Template.nupkg",
+ GettextCatalog.GetString (string.Format (".NET Core SDK {0} NUnit Project Templates NuGet package path", SupportedSDK [i]))
+ );
}
}
diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTests.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTests.cs
index 591703c5c2..0d59090465 100644
--- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTests.cs
+++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTests.cs
@@ -291,6 +291,10 @@ namespace MonoDevelop.DotNetCore.Tests
File.WriteAllText (fileName, string.Empty);
Assert.AreEqual ("EmbeddedResource", project.GetDefaultBuildAction (fileName));
+ fileName = project.BaseDirectory.Combine ("sample.ts");
+ File.WriteAllText (fileName, string.Empty);
+ Assert.AreEqual ("TypeScriptCompile", project.GetDefaultBuildAction (fileName));
+
fileName = project.BaseDirectory.Combine ("wwwroot", "MyPage.html");
Directory.CreateDirectory (fileName.ParentDirectory);
File.WriteAllText (fileName, string.Empty);
diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs
index a005019c12..d44a4f2ff9 100644
--- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs
+++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs
@@ -167,8 +167,10 @@ namespace MonoDevelop.DotNetCore
else
outputFileName = GetOutputFileName (configuration);
+ var workingDirectory = Project.GetOutputFileName (configSel).ParentDirectory;
+
return new DotNetCoreExecutionCommand (
- string.IsNullOrEmpty (dotnetCoreRunConfiguration?.StartWorkingDirectory) ? Project.BaseDirectory : dotnetCoreRunConfiguration.StartWorkingDirectory,
+ string.IsNullOrEmpty (dotnetCoreRunConfiguration?.StartWorkingDirectory) ? workingDirectory : dotnetCoreRunConfiguration.StartWorkingDirectory,
outputFileName,
dotnetCoreRunConfiguration?.StartArguments
) {
diff --git a/main/src/addins/MonoDevelop.DotNetCore/Properties/MonoDevelop.DotNetCore.addin.xml b/main/src/addins/MonoDevelop.DotNetCore/Properties/MonoDevelop.DotNetCore.addin.xml
index 3dea9bc528..f79b5f284f 100644
--- a/main/src/addins/MonoDevelop.DotNetCore/Properties/MonoDevelop.DotNetCore.addin.xml
+++ b/main/src/addins/MonoDevelop.DotNetCore/Properties/MonoDevelop.DotNetCore.addin.xml
@@ -109,6 +109,42 @@
condition="UseNetCore21=true"
category="netcore/app/general"/>
</Condition>
+ <Template
+ id="NUnit3.DotNetNew.Template.CSharp"
+ templateId="NUnit3.DotNetNew.Template.CSharp"
+ _overrideName="NUnit Test Project"
+ _overrideDescription="Creates a new NUnit test project."
+ path="${DotNetCoreSdk.2.1.Templates.NUnit3.DotNetNew.Template.nupkg}"
+ icon="md-netcore-test-project"
+ imageId="md-netcore-test-project"
+ wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
+ condition="UseNetCore21=true"
+ category="netcore/test/general" />
+ <Template
+ id="NUnit3.DotNetNew.Template.FSharp"
+ templateId="NUnit3.DotNetNew.Template.FSharp"
+ _overrideName="NUnit Test Project"
+ _overrideDescription="Creates a new NUnit test project."
+ path="${DotNetCoreSdk.2.1.Templates.NUnit3.DotNetNew.Template.nupkg}"
+ icon="md-netcore-test-project"
+ imageId="md-netcore-test-project"
+ wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
+ condition="UseNetCore21=true"
+ category="netcore/test/general" />
+ <Condition id="FeatureSwitch" name="VBNetDotnetCoreTemplates">
+ <Template
+ id="NUnit3.DotNetNew.Template.VisualBasic"
+ templateId="NUnit3.DotNetNew.Template.VisualBasic"
+ _overrideName="NUnit Test Project"
+ _overrideDescription="Creates a new NUnit test project."
+ overrideLanguage="VBNet"
+ path="${DotNetCoreSdk.2.1.Templates.NUnit3.DotNetNew.Template.nupkg}"
+ icon="md-netcore-test-project"
+ imageId="md-netcore-test-project"
+ wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
+ condition="UseNetCore21=true"
+ category="netcore/test/general" />
+ </Condition>
</Condition>
<Condition id="DotNetCoreSdkInstalled" sdkVersion="2.2">
<Template
@@ -973,7 +1009,7 @@
icon="md-netcore-test-project"
imageId="md-netcore-test-project"
wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
- condition="UseNetCore21=true"
+ condition="UseNetCore22=true"
category="netcore/test/general" />
<Template
id="NUnit3.DotNetNew.Template.FSharp"
@@ -984,7 +1020,7 @@
icon="md-netcore-test-project"
imageId="md-netcore-test-project"
wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
- condition="UseNetCore21=true"
+ condition="UseNetCore22=true"
category="netcore/test/general" />
<Condition id="FeatureSwitch" name="VBNetDotnetCoreTemplates">
<Template
@@ -997,7 +1033,7 @@
icon="md-netcore-test-project"
imageId="md-netcore-test-project"
wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
- condition="UseNetCore21=true"
+ condition="UseNetCore22=true"
category="netcore/test/general" />
</Condition>
</Condition>
diff --git a/main/src/addins/MonoDevelop.GtkCore/MonoDevelop.GtkCore.GuiBuilder/GuiBuilderService.cs b/main/src/addins/MonoDevelop.GtkCore/MonoDevelop.GtkCore.GuiBuilder/GuiBuilderService.cs
index bb545fe25d..70c3b40850 100644
--- a/main/src/addins/MonoDevelop.GtkCore/MonoDevelop.GtkCore.GuiBuilder/GuiBuilderService.cs
+++ b/main/src/addins/MonoDevelop.GtkCore/MonoDevelop.GtkCore.GuiBuilder/GuiBuilderService.cs
@@ -218,7 +218,7 @@ namespace MonoDevelop.GtkCore.GuiBuilder
if (!exists) {
Pad p = IdeApp.Workbench.GetPad<MonoDevelop.DesignerSupport.ToolboxPad> ();
if (p != null) p.Visible = true;
- p = IdeApp.Workbench.GetPad<MonoDevelop.DesignerSupport.PropertyPad> ();
+ p = IdeApp.Workbench.GetPad<MonoDevelop.DesignerSupport.IPropertyPad> ();
if (p != null) p.Visible = true;
}
}
diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj
index 46ef173f35..a8dd71b6de 100644
--- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj
+++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj
@@ -199,6 +199,7 @@
<Compile Include="MonoDevelop.PackageManagement.Tests\ProjectReferenceMaintainerTests.cs" />
<Compile Include="MonoDevelop.PackageManagement.Tests\FullyQualifiedReferencePathTests.cs" />
<Compile Include="MonoDevelop.PackageManagement.Tests\MSBuildPackageSpecCreatorTests.cs" />
+ <Compile Include="MonoDevelop.PackageManagement.Tests\InstallPackageWithAvailableItemNameTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\core\MonoDevelop.Core\MonoDevelop.Core.csproj">
diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/InstallPackageWithAvailableItemNameTests.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/InstallPackageWithAvailableItemNameTests.cs
new file mode 100644
index 0000000000..c32ec699b7
--- /dev/null
+++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/InstallPackageWithAvailableItemNameTests.cs
@@ -0,0 +1,74 @@
+//
+// InstallPackageWithAvailableItemNameTests.cs
+//
+// Author:
+// Matt Ward <matt.ward@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// 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.Linq;
+using System.Threading.Tasks;
+using MonoDevelop.PackageManagement.Tests.Helpers;
+using MonoDevelop.Projects;
+using NuGet.Versioning;
+using NUnit.Framework;
+using UnitTests;
+
+namespace MonoDevelop.PackageManagement.Tests
+{
+ [TestFixture]
+ public class InstallPackageWithAvailableItemNameTests : RestoreTestBase
+ {
+ [Test]
+ public async Task InstallPackage_PackageDefinesCustomAvailableItemNames_BuildActionsIncludeCustomAvailableItemNames ()
+ {
+ string solutionFileName = Util.GetSampleProject ("RestoreStylePackageReference", "RestoreStylePackageReference.sln");
+ using (solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName)) {
+ CreateNuGetConfigFile (solution.BaseDirectory);
+ var project = (DotNetProject)solution.FindProjectByName ("RestoreStylePackageReference");
+
+ var originalBuildActions = project.GetBuildActions ();
+ await InstallNuGetPackage (project, "Test.Xam.AvailableItemName", "0.1.0");
+ var updatedBuildActions = project.GetBuildActions ();
+
+ Assert.IsFalse (originalBuildActions.Contains ("TestXamAvailableItem"));
+ Assert.That (updatedBuildActions, Contains.Item ("TestXamAvailableItem"));
+ }
+ }
+
+ Task InstallNuGetPackage (DotNetProject project, string packageId, string packageVersion)
+ {
+ var solutionManager = new MonoDevelopSolutionManager (project.ParentSolution);
+ var context = CreateNuGetProjectContext (solutionManager.Settings);
+ var sources = solutionManager.CreateSourceRepositoryProvider ().GetRepositories ();
+
+ var action = new InstallNuGetPackageAction (sources, solutionManager, new DotNetProjectProxy (project), context);
+ action.LicensesMustBeAccepted = false;
+ action.OpenReadmeFile = false;
+ action.PackageId = packageId;
+ action.Version = NuGetVersion.Parse (packageVersion);
+
+ return Task.Run (() => {
+ action.Execute ();
+ });
+ }
+ }
+}
diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackageReferenceNuGetProjectTests.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackageReferenceNuGetProjectTests.cs
index 2167100d23..23aaedc1fa 100644
--- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackageReferenceNuGetProjectTests.cs
+++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackageReferenceNuGetProjectTests.cs
@@ -24,12 +24,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MonoDevelop.Core;
using MonoDevelop.PackageManagement.Tests.Helpers;
using MonoDevelop.Projects;
+using NuGet.PackageManagement;
using NuGet.Packaging.Core;
using NuGet.ProjectManagement;
using NuGet.ProjectModel;
@@ -388,5 +390,45 @@ namespace MonoDevelop.PackageManagement.Tests
int projectItemsCount = dotNetProject.Files.Count;
Assert.AreEqual (1, projectItemsCount);
}
+
+ [Test]
+ public void OnAfterExecuteActions_PackageInstallAction_PackageInstalledEventFired ()
+ {
+ CreateNuGetProject ();
+ var packageIdentity = new PackageIdentity ("Test", NuGetVersion.Parse ("1.2"));
+ var actions = new List<NuGetProjectAction> ();
+ var action = NuGetProjectAction.CreateInstallProjectAction (packageIdentity, null, project);
+ actions.Add (action);
+ PackageManagementEventArgs eventArgs = null;
+ project.PackageManagementEvents.PackageInstalled += (sender, e) => {
+ eventArgs = e;
+ };
+
+ project.OnAfterExecuteActions (actions);
+
+ Assert.AreEqual ("Test", eventArgs.Id);
+ Assert.AreEqual ("1.2", eventArgs.Version.ToString ());
+ Assert.AreEqual (packageIdentity, eventArgs.Package);
+ }
+
+ [Test]
+ public void OnAfterExecuteActions_PackageUninstallAction_PackageUninstalledEventFired ()
+ {
+ CreateNuGetProject ();
+ var packageIdentity = new PackageIdentity ("Test", NuGetVersion.Parse ("1.2"));
+ var actions = new List<NuGetProjectAction> ();
+ var action = NuGetProjectAction.CreateUninstallProjectAction (packageIdentity, project);
+ actions.Add (action);
+ PackageManagementEventArgs eventArgs = null;
+ project.PackageManagementEvents.PackageUninstalled += (sender, e) => {
+ eventArgs = e;
+ };
+
+ project.OnAfterExecuteActions (actions);
+
+ Assert.AreEqual ("Test", eventArgs.Id);
+ Assert.AreEqual ("1.2", eventArgs.Version.ToString ());
+ Assert.AreEqual (packageIdentity, eventArgs.Package);
+ }
}
}
diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/PackageReferenceNuGetProject.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/PackageReferenceNuGetProject.cs
index 575200ece5..4892485906 100644
--- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/PackageReferenceNuGetProject.cs
+++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/PackageReferenceNuGetProject.cs
@@ -51,19 +51,20 @@ namespace MonoDevelop.PackageManagement
{
DotNetProject project;
ConfigurationSelector configuration;
- IPackageManagementEvents packageManagementEvents;
+ PackageManagementEvents packageManagementEvents;
string msbuildProjectPath;
string projectName;
+ bool reevaluationRequired;
public PackageReferenceNuGetProject (DotNetProject project, ConfigurationSelector configuration)
- : this (project, configuration, PackageManagementServices.PackageManagementEvents)
+ : this (project, configuration, (PackageManagementEvents)PackageManagementServices.PackageManagementEvents)
{
}
public PackageReferenceNuGetProject (
DotNetProject project,
ConfigurationSelector configuration,
- IPackageManagementEvents packageManagementEvents)
+ PackageManagementEvents packageManagementEvents)
{
this.project = project;
this.configuration = configuration;
@@ -241,13 +242,16 @@ namespace MonoDevelop.PackageManagement
throw new InvalidOperationException (GettextCatalog.GetString ("Unable to create package spec for project. '{0}'", project.FileName));
}
- public override Task PostProcessAsync (INuGetProjectContext nuGetProjectContext, CancellationToken token)
+ public override async Task PostProcessAsync (INuGetProjectContext nuGetProjectContext, CancellationToken token)
{
- Runtime.RunInMainThread (() => {
+ await Runtime.RunInMainThread (async () => {
+ if (reevaluationRequired) {
+ await DotNetProject.ReevaluateProject (new ProgressMonitor ());
+ }
DotNetProject.NotifyModified ("References");
});
- return base.PostProcessAsync (nuGetProjectContext, token);
+ await base.PostProcessAsync (nuGetProjectContext, token);
}
public void OnBeforeUninstall (IEnumerable<NuGetProjectAction> actions)
@@ -256,6 +260,16 @@ namespace MonoDevelop.PackageManagement
public void OnAfterExecuteActions (IEnumerable<NuGetProjectAction> actions)
{
+ reevaluationRequired = actions.Any (action => action.NuGetProjectActionType == NuGetProjectActionType.Install);
+
+ foreach (var action in actions) {
+ var eventArgs = new PackageEventArgs (this, action.PackageIdentity, null);
+ if (action.NuGetProjectActionType == NuGetProjectActionType.Install) {
+ packageManagementEvents.OnPackageInstalled (Project, eventArgs);
+ } else if (action.NuGetProjectActionType == NuGetProjectActionType.Uninstall) {
+ packageManagementEvents.OnPackageUninstalled (Project, eventArgs);
+ }
+ }
}
public void NotifyProjectReferencesChanged (bool includeTransitiveProjectReferences)
diff --git a/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/NuGetPackageMetadata.cs b/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/NuGetPackageMetadata.cs
index 572ef2910a..d786129336 100644
--- a/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/NuGetPackageMetadata.cs
+++ b/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/NuGetPackageMetadata.cs
@@ -70,6 +70,7 @@ namespace MonoDevelop.Packaging
Id = GetProperty (propertyGroup, PackageIdPropertyName);
Version = GetProperty (propertyGroup, "PackageVersion");
Authors = GetProperty (propertyGroup, "Authors");
+ Copyright = GetProperty (propertyGroup, "Copyright");
DevelopmentDependency = GetProperty (propertyGroup, "DevelopmentDependency", false);
IconUrl = GetProperty (propertyGroup, "PackageIconUrl");
Language = GetProperty (propertyGroup, "NeutralLanguage");
@@ -107,6 +108,7 @@ namespace MonoDevelop.Packaging
SetProperty (propertyGroup, PackageIdPropertyName, Id);
SetProperty (propertyGroup, "PackageVersion", Version);
SetProperty (propertyGroup, "Authors", Authors);
+ SetProperty (propertyGroup, "Copyright", Copyright);
SetProperty (propertyGroup, "DevelopmentDependency", DevelopmentDependency);
SetProperty (propertyGroup, "PackageIconUrl", IconUrl);
SetProperty (propertyGroup, "NeutralLanguage", Language);
diff --git a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs
index d2f924732c..c91f7683c1 100644
--- a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs
+++ b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs
@@ -1487,8 +1487,9 @@ namespace MonoDevelop.SourceEditor
} else if (args.Button == 1) {
if (!string.IsNullOrEmpty (Document.FileName)) {
if (args.LineSegment != null) {
- int column = TextEditor.Caret.Line == args.LineNumber ? TextEditor.Caret.Column : 1;
-
+ int column = TextEditor.Caret.Line == args.LineNumber ?
+ Math.Min (TextEditor.Caret.Column, args.LineSegment.Length) : 1;
+
lock (breakpoints)
breakpoints.Toggle (Document.FileName, args.LineNumber, column);
}
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj
index 7d832ef65b..570f99ad9a 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj
@@ -64,6 +64,7 @@
<Compile Include="Gui\MonoDevelop.VersionControl.Git.StashManagerDialog.cs" />
<Compile Include="Gui\MonoDevelop.VersionControl.Git.UserGitConfigDialog.cs" />
<Compile Include="Gui\MonoDevelop.VersionControl.Git.UserInfoConflictDialog.cs" />
+ <Compile Include="MonoDevelop.VersionControl.Git\IGitCredentialsProvider.cs" />
<Compile Include="MonoDevelop.VersionControl.Git\XwtCredentialsDialog.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitCredentials.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitCredentials.cs
index 3f20f8158c..acec1f971a 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitCredentials.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitCredentials.cs
@@ -23,14 +23,16 @@
// 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;
using MonoDevelop.Core;
using MonoDevelop.Ide;
using LibGit2Sharp;
using System.IO;
using System.Collections.Generic;
using MonoDevelop.Components;
+using System.Linq;
+using Mono.Addins;
namespace MonoDevelop.VersionControl.Git
{
@@ -120,9 +122,7 @@ namespace MonoDevelop.VersionControl.Git
// if the password store contains an invalid password/no password
if ((types & SupportedCredentialTypes.UsernamePassword) != 0) {
if (Uri.TryCreate (url, UriKind.RelativeOrAbsolute, out uri)) {
- string username;
- string password;
- if (!state.NativePasswordUsed && TryGetUsernamePassword (uri, out username, out password)) {
+ if (!state.NativePasswordUsed && TryGetUsernamePassword (uri, out var username, out var password)) {
state.NativePasswordUsed = true;
return new UsernamePasswordCredentials {
Username = username,
@@ -202,7 +202,25 @@ namespace MonoDevelop.VersionControl.Git
return cred;
}
- if (XwtCredentialsDialog.Run (url, types, cred).Result) {
+ var gitCredentialsProviders = AddinManager.GetExtensionObjects<IGitCredentialsProvider> ();
+
+ if (gitCredentialsProviders != null) {
+ foreach (var gitCredentialsProvider in gitCredentialsProviders) {
+ if (gitCredentialsProvider.SupportsUrl (url)) {
+ var providerResult = GetCredentialsFromProvider (gitCredentialsProvider, url, types, cred);
+ if (providerResult == GitCredentialsProviderResult.Cancelled)
+ throw new UserCancelledException (UserCancelledExceptionMessage);
+ if (result = providerResult == GitCredentialsProviderResult.Found)
+ break;
+ }
+ }
+ }
+
+ if (!result) {
+ result = GetCredentials (url, types, cred);
+ }
+
+ if (result) {
if ((types & SupportedCredentialTypes.UsernamePassword) != 0) {
var upcred = (UsernamePasswordCredentials)cred;
if (!string.IsNullOrEmpty (upcred.Password) && uri != null) {
@@ -215,6 +233,26 @@ namespace MonoDevelop.VersionControl.Git
throw new UserCancelledException (UserCancelledExceptionMessage);
}
+ static GitCredentialsProviderResult GetCredentialsFromProvider (IGitCredentialsProvider gitCredentialsProvider, string uri, SupportedCredentialTypes type, Credentials cred)
+ {
+ if (type != SupportedCredentialTypes.UsernamePassword)
+ return GitCredentialsProviderResult.NotFound;
+
+ var (result, credentials) = gitCredentialsProvider.TryGetCredentialsAsync (uri).Result;
+
+ if (result == GitCredentialsProviderResult.Found) {
+ ((UsernamePasswordCredentials)cred).Username = credentials.Username;
+ ((UsernamePasswordCredentials)cred).Password = credentials.Password;
+ }
+
+ return result;
+ }
+
+ static bool GetCredentials (string uri, SupportedCredentialTypes type, Credentials cred)
+ {
+ return XwtCredentialsDialog.Run (uri, type, cred).Result;
+ }
+
internal static bool KeyHasPassphrase (string key)
{
return File.ReadAllText (key).Contains ("Proc-Type: 4,ENCRYPTED");
@@ -235,6 +273,10 @@ namespace MonoDevelop.VersionControl.Git
static bool TryGetUsernamePassword (Uri uri, out string username, out string password)
{
var cred = PasswordService.GetWebUserNameAndPassword (uri);
+ // if the Uri has a path, fallback to base Uri if available
+ if (cred == null && !string.IsNullOrEmpty (uri.PathAndQuery) && Uri.TryCreate (uri.GetLeftPart (UriPartial.Authority), UriKind.Absolute, out var baseUri)) {
+ cred = PasswordService.GetWebUserNameAndPassword (baseUri);
+ }
if (cred != null) {
username = cred.Item1;
password = cred.Item2;
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitVersionControl.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitVersionControl.cs
index 23b0c85e4b..eaa0f68658 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitVersionControl.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitVersionControl.cs
@@ -32,7 +32,9 @@ namespace MonoDevelop.VersionControl.Git
{
abstract class GitVersionControl : VersionControlSystem
{
- string version = null;
+ string version = null;
+
+ const string GitExtension = ".git";
public override string Name {
get { return "Git"; }
@@ -72,10 +74,19 @@ namespace MonoDevelop.VersionControl.Git
string repo = LibGit2Sharp.Repository.Discover (path.ResolveLinks ());
if (!string.IsNullOrEmpty (repo)) {
repo = repo.TrimEnd ('\\', '/');
- if (repo.EndsWith (".git", System.StringComparison.OrdinalIgnoreCase))
+ if (repo.EndsWith (GitExtension, System.StringComparison.OrdinalIgnoreCase))
repo = Path.GetDirectoryName (repo);
}
return repo;
}
+
+ public override string GetRelativeCheckoutPathForRemote (string remoteRelativePath)
+ {
+ remoteRelativePath = base.GetRelativeCheckoutPathForRemote (remoteRelativePath);
+ if (remoteRelativePath.EndsWith (GitExtension, System.StringComparison.CurrentCultureIgnoreCase)) {
+ remoteRelativePath = remoteRelativePath.Substring (0, remoteRelativePath.Length - GitExtension.Length);
+ }
+ return remoteRelativePath;
+ }
}
}
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/IGitCredentialsProvider.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/IGitCredentialsProvider.cs
new file mode 100644
index 0000000000..abf7bda887
--- /dev/null
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/IGitCredentialsProvider.cs
@@ -0,0 +1,57 @@
+//
+// IGitCredentialsProvider.cs
+//
+// Author:
+// Javier Suárez Ruiz <jsuarez@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// 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.Threading.Tasks;
+using Mono.Addins;
+
+namespace MonoDevelop.VersionControl.Git
+{
+ [TypeExtensionPoint]
+ public interface IGitCredentialsProvider
+ {
+ bool SupportsUrl (string url);
+ Task<(GitCredentialsProviderResult result, GitCredential credentials)> TryGetCredentialsAsync (string url);
+ }
+
+ public enum GitCredentialsProviderResult
+ {
+ Found,
+ NotFound,
+ Cancelled,
+ }
+
+ public class GitCredential
+ {
+ public GitCredential (string username, string password)
+ {
+ Username = username;
+ Password = password;
+ }
+
+ public string Username { get; }
+ public string Password { get; }
+ }
+} \ No newline at end of file
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs
index 9df102723f..718adcd7ab 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs
@@ -37,6 +37,8 @@ namespace MonoDevelop.VersionControl.Dialogs
{
Build ();
+ GtkWorkarounds.DisableMinimizeMaximizeButtons (this);
+ Modal = true;
foreach (VersionControlSystem vcs in VersionControlService.GetVersionControlSystems ()) {
if (vcs.IsInstalled) {
repCombo.AppendText (vcs.Name);
@@ -389,7 +391,7 @@ namespace MonoDevelop.VersionControl.Dialogs
void AppendRelativePath ()
{
- UrlBasedRepositoryEditor edit = currentEditor as UrlBasedRepositoryEditor;
+ var edit = currentEditor as UrlBasedRepositoryEditor;
if (edit == null)
return;
@@ -399,7 +401,8 @@ namespace MonoDevelop.VersionControl.Dialogs
return;
}
- entryFolder.Text = defaultPath + edit.RelativePath.Replace ('/', System.IO.Path.DirectorySeparatorChar);
+ var vcs = systems [repCombo.Active];
+ entryFolder.Text = defaultPath + vcs.GetRelativeCheckoutPathForRemote (edit.RelativePath);
}
}
}
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/MergeView.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/MergeView.cs
index 8d9d056455..848979ccbe 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/MergeView.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/MergeView.cs
@@ -25,6 +25,7 @@
// THE SOFTWARE.
using MonoDevelop.Components;
using MonoDevelop.Core;
+using System.Linq;
namespace MonoDevelop.VersionControl.Views
{
@@ -34,36 +35,113 @@ namespace MonoDevelop.VersionControl.Views
class MergeView : BaseView, IMergeView
{
- VersionControlDocumentInfo info;
+ readonly VersionControlDocumentInfo info;
+ readonly FileEventInfo fileEventInfo;
MergeWidget widget;
+ readonly MergeWidgetContainer widgetContainer;
+ readonly Gtk.Label NoMergeConflictsLabel;
- public override Control Control {
- get {
+ public override Control Control => widgetContainer;
+
+ public MergeView (VersionControlDocumentInfo info) : base (GettextCatalog.GetString ("Merge"), GettextCatalog.GetString ("Shows the merge view for the current file"))
+ {
+ this.info = info;
+ fileEventInfo = new FileEventInfo (info.Item.Path.FullPath, info.Item.IsDirectory);
+ widgetContainer = new MergeWidgetContainer ();
+ NoMergeConflictsLabel = new Gtk.Label () { Text = GettextCatalog.GetString ("No merge conflicts detected.") };
+ FileService.FileChanged += FileService_FileChanged;
+ }
+
+ void RefreshContent ()
+ {
+ var isConflicted = info?.Item?.VersionInfo?.Status.HasFlag (VersionStatus.Conflicted) ?? false;
+ if (isConflicted) {
if (widget == null) {
widget = new MergeWidget ();
widget.Load (info);
}
-
- return widget;
+ if (widgetContainer.Content != widget) {
+ widgetContainer.Content = widget;
+ }
+ } else {
+ if (widgetContainer.Content != NoMergeConflictsLabel) {
+ widgetContainer.Content = NoMergeConflictsLabel;
+ }
}
}
- public MergeView (VersionControlDocumentInfo info) : base (GettextCatalog.GetString ("Merge"), GettextCatalog.GetString ("Shows the merge view for the current file"))
+ void FileService_FileChanged (object sender, FileEventArgs e)
{
- this.info = info;
+ //content is null when is deselected
+ if (widgetContainer.Content == null) {
+ return;
+ }
+
+ //continue only if file server detected some change in this file
+ if (e.All (s => s.FileName.CompareTo (fileEventInfo.FileName) < 0)) {
+ return;
+ }
+
+ //if it is shown we refresh we show the content and refresh the editor (probably this nee
+ info.Start ();
+ RefreshContent ();
+ RefreshMergeEditor ();
}
protected override void OnSelected ()
{
- widget.UpdateLocalText ();
- widget.info.Start ();
+ info.Start ();
+ RefreshContent ();
+ RefreshMergeEditor ();
+ }
- var buffer = info.Document.GetContent<MonoDevelop.Ide.Editor.TextEditor> ();
- if (buffer != null) {
- var loc = buffer.CaretLocation;
- int line = loc.Line < 1 ? 1 : loc.Line;
- int column = loc.Column < 1 ? 1 : loc.Column;
- widget.MainEditor.SetCaretTo (line, column);
+ void RefreshMergeEditor ()
+ {
+ if (widgetContainer.Content is MergeWidget) {
+ widget.UpdateLocalText ();
+ var buffer = info.Document.GetContent<MonoDevelop.Ide.Editor.TextEditor> ();
+ if (buffer != null) {
+ var loc = buffer.CaretLocation;
+ int line = loc.Line < 1 ? 1 : loc.Line;
+ int column = loc.Column < 1 ? 1 : loc.Column;
+ widget.MainEditor.SetCaretTo (line, column);
+ }
+ }
+ }
+
+ void ClearContainer () => widgetContainer.Clear ();
+
+ protected override void OnDeselected () => ClearContainer ();
+
+ public override void Dispose ()
+ {
+ ClearContainer ();
+ FileService.FileChanged -= FileService_FileChanged;
+ base.Dispose ();
+ }
+
+ class MergeWidgetContainer : Gtk.VBox
+ {
+ Gtk.Widget content;
+ public Gtk.Widget Content {
+ get => content;
+ set {
+ if (content == value) {
+ return;
+ }
+ Clear ();
+ content = value;
+ PackStart (value, true, true, 0);
+ ShowAll ();
+ }
+ }
+
+ public void Clear ()
+ {
+ if (content != null) {
+ Remove (content);
+ content = null;
+ }
}
}
}
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs
index 60484eb459..18f500f298 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs
@@ -17,6 +17,7 @@ using Mono.Addins;
using MonoDevelop.Ide;
using MonoDevelop.Core.ProgressMonitoring;
using MonoDevelop.Core.Instrumentation;
+using System.Collections.Concurrent;
namespace MonoDevelop.VersionControl
{
@@ -104,14 +105,23 @@ namespace MonoDevelop.VersionControl
VersionControlSystem vcs;
try {
- vcs = (VersionControlSystem) args.ExtensionObject;
+ vcs = (VersionControlSystem)args.ExtensionObject;
} catch (Exception e) {
LoggingService.LogError ("Failed to initialize VersionControlSystem type.", e);
return;
}
if (args.Change == ExtensionChange.Add) {
- handlers.Add (vcs);
+ IComparer<VersionControlSystem> compare = new CompareVersionControlSystem ();
+
+ int search = handlers.BinarySearch (vcs, compare);
+
+ if (search < 0)
+ handlers.Insert (~search, vcs);
+ else {
+ LoggingService.LogError ("Adding new version control system {0} failed, the name {1} is already reserved.", vcs.GetType ().Name, vcs.Name);
+ return;
+ }
try {
// Include the repository type in the serialization context, so repositories
// of this type can be deserialized from the configuration file.
@@ -122,8 +132,7 @@ namespace MonoDevelop.VersionControl
} catch (Exception e) {
LoggingService.LogError ("Error while adding version control system.", e);
}
- }
- else {
+ } else {
handlers.Remove (vcs);
}
}
@@ -202,7 +211,7 @@ namespace MonoDevelop.VersionControl
return String.Empty;
}
- internal static Dictionary<Repository, InternalRepositoryReference> referenceCache = new Dictionary<Repository, InternalRepositoryReference> ();
+ internal static ConcurrentDictionary<Repository, InternalRepositoryReference> referenceCache = new ConcurrentDictionary<Repository, InternalRepositoryReference> ();
public static Repository GetRepository (WorkspaceObject entry)
{
if (IsGloballyDisabled)
@@ -216,17 +225,14 @@ namespace MonoDevelop.VersionControl
InternalRepositoryReference rref = null;
if (repo != null) {
repo.AddRef ();
- if (!referenceCache.TryGetValue (repo, out rref)) {
- rref = new InternalRepositoryReference (repo);
- referenceCache [repo] = rref;
- }
+ rref = referenceCache.GetOrAdd (repo, r => new InternalRepositoryReference (r));
}
entry.ExtendedProperties [typeof(InternalRepositoryReference)] = rref;
return repo;
}
- internal static readonly Dictionary<FilePath,Repository> repositoryCache = new Dictionary<FilePath,Repository> ();
+ internal static readonly ConcurrentDictionary<FilePath,Repository> repositoryCache = new ConcurrentDictionary<FilePath,Repository> ();
public static Repository GetRepositoryReference (string path, string id)
{
VersionControlSystem detectedVCS = null;
@@ -249,18 +255,21 @@ namespace MonoDevelop.VersionControl
}
bestMatch = bestMatch.CanonicalPath;
- if (repositoryCache.TryGetValue (bestMatch, out var repository))
- return repository;
try {
- var repo = detectedVCS?.GetRepositoryReference (bestMatch, id);
- if (repo != null) {
- repositoryCache.Add (bestMatch, repo);
- Instrumentation.Repositories.Inc (new RepositoryMetadata (detectedVCS));
- }
- return repo;
+ return repositoryCache.GetOrAdd (bestMatch, p => {
+ var result = detectedVCS?.GetRepositoryReference (p, id);
+ if (result != null) {
+ Instrumentation.Repositories.Inc (new RepositoryMetadata (detectedVCS));
+ return result;
+ }
+ // never add null values
+ throw new ArgumentNullException ("result");
+ });
} catch (Exception e) {
- LoggingService.LogError ($"Could not query {detectedVCS.Name} repository reference", e);
+ // ArgumentNullException for "result" is expected when GetRepositoryReference returns null, no need to log
+ if (!(e is ArgumentNullException ne) || ne.ParamName != "result")
+ LoggingService.LogInternalError ($"Could not query {detectedVCS.Name} repository reference", e);
return null;
}
}
@@ -824,8 +833,8 @@ namespace MonoDevelop.VersionControl
public void Dispose ()
{
- VersionControlService.referenceCache.Remove (repo);
- VersionControlService.repositoryCache.Remove (repo.RootPath.CanonicalPath);
+ VersionControlService.referenceCache.TryRemove (repo, out _);
+ VersionControlService.repositoryCache.TryRemove (repo.RootPath.CanonicalPath, out _);
repo.Unref ();
}
}
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlSystem.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlSystem.cs
index 43a54eb653..7c77fe5a88 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlSystem.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlSystem.cs
@@ -1,3 +1,5 @@
+using System;
+using System.Collections.Generic;
using MonoDevelop.Core;
namespace MonoDevelop.VersionControl
@@ -28,9 +30,9 @@ namespace MonoDevelop.VersionControl
/// The default implementation returns the full name of the class.
/// </remarks>
public virtual string Id {
- get { return GetType().ToString(); }
+ get { return GetType ().ToString (); }
}
-
+
/// <summary>
/// Display name of the version control system
/// </summary>
@@ -54,12 +56,12 @@ namespace MonoDevelop.VersionControl
public virtual bool IsInstalled {
get { return false; }
}
-
+
/// <summary>
/// Creates an instance of a repository for this version control system
/// </summary>
protected abstract Repository OnCreateRepositoryInstance ();
-
+
/// <summary>
/// Creates an editor object for a repository.
/// </summary>
@@ -69,7 +71,7 @@ namespace MonoDevelop.VersionControl
/// <param name='repo'>
/// A repository
/// </param>
- public abstract IRepositoryEditor CreateRepositoryEditor (Repository repo);
+ public abstract IRepositoryEditor CreateRepositoryEditor (Repository repo);
/// <summary>
/// Gets a repository for a given local path and identifier
@@ -111,5 +113,37 @@ namespace MonoDevelop.VersionControl
/// <param name="path">The path to start the repository detection from.</param>
/// <param name="id">An identifier. This identifier is generated by MD and normally identifiers a project.</param>
protected abstract FilePath OnGetRepositoryPath (FilePath path, string id);
+
+ /// <summary>
+ /// Gets the output directory path.
+ /// </summary>
+ /// <returns>Returns the relative path based on the remote path.</returns>
+ /// <param name="remoteRelativePath">Remote Relative Path.</param>
+ public virtual string GetRelativeCheckoutPathForRemote (string remoteRelativePath)
+ {
+ return remoteRelativePath.Replace ('/', System.IO.Path.DirectorySeparatorChar);
+ }
+ }
+
+ public class CompareVersionControlSystem : IComparer<VersionControlSystem>
+ {
+ public int Compare (VersionControlSystem vcs1, VersionControlSystem vcs2)
+ {
+ int result;
+
+ if (ReferenceEquals (vcs1, vcs2)) {
+ result = 0;
+ } else {
+ if (vcs1 is null) {
+ result = 1;
+ } else if (vcs2 is null) {
+ result = -1;
+ } else {
+ result = string.Compare(vcs1.Name, vcs2.Name, StringComparison.InvariantCultureIgnoreCase);
+ }
+ }
+
+ return result;
+ }
}
-}
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
index 5eb20c4b65..81221d827b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
@@ -334,8 +334,6 @@ namespace MonoDevelop.Core
public static void NotifyFilesChanged (IEnumerable<FilePath> files, bool autoReload)
{
try {
- foreach (var fsFiles in files.GroupBy (f => GetFileSystemForPath (f, false)))
- fsFiles.Key.NotifyFilesChanged (fsFiles);
OnFileChanged (new FileEventArgs (files, false));
} catch (Exception ex) {
LoggingService.LogError ("File change notification failed", ex);
@@ -1015,6 +1013,16 @@ namespace MonoDevelop.Core
foreach (var ev in pendingProcess.Events)
ev.Invoke ();
}).Ignore ();
+
+ Task.Run (() => {
+ foreach (var ev in pendingProcess.Events) {
+ if (!(ev is FileEventData fev) || fev.Kind != FileService.EventDataKind.Changed)
+ continue;
+
+ foreach (var fsFiles in fev.Args.GroupBy (f => FileService.GetFileSystemForPath (f.FileName, false)))
+ fsFiles.Key.NotifyFilesChanged (fsFiles.Select (x => x.FileName));
+ }
+ }).Ignore ();
}
public void RaiseEvent (FileService.EventDataKind kind, FileEventArgs args)
@@ -1030,6 +1038,11 @@ namespace MonoDevelop.Core
}
}
+ if (kind == FileService.EventDataKind.Changed) {
+ foreach (var fsFiles in args.GroupBy (f => FileService.GetFileSystemForPath (f.FileName, false)))
+ fsFiles.Key.NotifyFilesChanged (fsFiles.Select (x => x.FileName));
+ }
+
if (Runtime.IsMainThread) {
RaiseSync (kind, args);
} else {
@@ -1332,17 +1345,24 @@ namespace MonoDevelop.Core
internal void OnFileCreated (FileEventArgs args)
{
- FileCreated?.Invoke (this, args);
+ FileCreated?.Invoke (this, Clone (args));
}
internal void OnFileRemoved (FileEventArgs args)
{
- FileRemoved?.Invoke (this, args);
+ FileRemoved?.Invoke (this, Clone (args));
}
internal void OnFileRenamed (FileCopyEventArgs args)
{
- FileRenamed?.Invoke (this, args);
+ FileRenamed?.Invoke (this, Clone (args));
+ }
+
+ static T Clone<T> (T args) where T : FileEventArgs, new()
+ {
+ var result = new T ();
+ result.AddRange (args);
+ return result;
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngine.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngine.cs
index 44b6f9dda3..ccf066aed9 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngine.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngine.cs
@@ -171,7 +171,8 @@ namespace MonoDevelop.Projects.MSBuild
try {
await connection.SendMessage (new UnloadProjectRequest { ProjectId = projectId }).ConfigureAwait (false);
} catch (Exception ex) {
- LoggingService.LogError ("Project unloading failed", ex);
+ if (alive)
+ LoggingService.LogError ("Project unloading failed", ex);
if (!await CheckDisconnected ())
throw;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs
index 447484027d..5c208ca77f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs
@@ -107,8 +107,16 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
base.OnReadProject (monitor, msproject);
var import = msproject.Imports.FirstOrDefault (im => im.Label == "Shared");
- if (import == null)
+ if (import == null) {
+ // Sanity check.
+ if (!StringComparer.OrdinalIgnoreCase.Equals (msproject.FileName.Extension, FileName.Extension)) {
+ // ProjectTypeGuid mismatch in solution file.
+ throw new InvalidOperationException (GettextCatalog.GetString (
+ "Project {0} is being loaded as a Shared Assets project but has a different file extension. Please check the project type GUID in the solution file is correct.",
+ Name));
+ }
return;
+ }
// TODO: load the type from msbuild
foreach (var item in msproject.Imports) {
@@ -183,7 +191,7 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
msproject.AddNewImport (@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props");
import = msproject.AddNewImport (MSBuildProjectService.ToMSBuildPath (FileName.ParentDirectory, projItemsPath));
import.Label = "Shared";
- if (LanguageName.Equals("C#", StringComparison.OrdinalIgnoreCase)) {
+ if (LanguageName == null || LanguageName.Equals("C#", StringComparison.OrdinalIgnoreCase)) {
msproject.AddNewImport (CSharptargets);
}
else if (LanguageName.Equals("F#", StringComparison.OrdinalIgnoreCase)) {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs
index 98c6874003..78d8b18fa5 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AsyncCriticalSection.cs
@@ -67,7 +67,13 @@ namespace MonoDevelop.Projects
locked = true;
return Task.FromResult (criticalSectionDisposer);
}
- var s = new TaskCompletionSource<IDisposable> ();
+
+ // When the TaskCompletionSource's SetResult method is called then all the async continuations waiting
+ // on this lock may be invoked synchronously. This can cause a stack overflow if many tasks are queued.
+ // To avoid this the continuations are run asynchronously by creating the TaskCompletionSource with
+ // TaskCreationOptions.RunContinuationsAsynchronously.
+ // https://stackoverflow.com/questions/28321457/taskcontinuationoptions-runcontinuationsasynchronously-and-stack-dives
+ var s = new TaskCompletionSource<IDisposable> (TaskCreationOptions.RunContinuationsAsynchronously);
queue.Enqueue (s);
return s.Task;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs
index 5b77e8be8e..2cf1311924 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs
@@ -63,6 +63,7 @@ namespace MonoDevelop.Projects
assembly = pset.GetValue ("AssemblyName");
signAssembly = pset.GetValue<bool> ("SignAssembly");
delaySign = pset.GetValue<bool> ("DelaySign");
+ PublicSign = pset.GetValue<bool> (nameof(PublicSign));
assemblyKeyFile = pset.GetPathValue ("AssemblyOriginatorKeyFile", FilePath.Empty);
if (string.IsNullOrEmpty (assemblyKeyFile))
assemblyKeyFile = pset.GetPathValue ("AssemblyKeyFile", FilePath.Empty);
@@ -76,6 +77,7 @@ namespace MonoDevelop.Projects
pset.SetValue ("AssemblyName", assembly, mergeToMainGroup: true);
pset.SetValue ("SignAssembly", signAssembly, defaultValue:false, mergeToMainGroup: true);
pset.SetValue ("DelaySign", delaySign, defaultValue:false, mergeToMainGroup:true);
+ pset.SetValue (nameof(PublicSign), PublicSign, defaultValue: false, mergeToMainGroup: true);
pset.SetValue ("AssemblyOriginatorKeyFile", assemblyKeyFile, defaultValue:FilePath.Empty, mergeToMainGroup:true);
if (compilationParameters != null)
compilationParameters.Write (pset);
@@ -93,6 +95,8 @@ namespace MonoDevelop.Projects
set { delaySign = value; }
}
+ public bool PublicSign { get; set; }
+
internal string OldAssemblyKeyFile {
set { assemblyKeyFile = value; }
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
index 2fcd862be2..d5599be9d8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
@@ -2772,6 +2772,9 @@ namespace MonoDevelop.Projects
// Read available item types
loadedAvailableItemNames = msproject.EvaluatedItems.Where (i => i.Name == "AvailableItemName").Select (i => i.Include).ToArray ();
+
+ // Ensure buildActions are refreshed if loadedAvailableItemNames have been updated.
+ buildActions = null;
}
List<ConfigData> GetConfigData (MSBuildProject msproject, bool includeEvaluated)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs
index e16b5ec29a..459a5b2359 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs
@@ -99,8 +99,11 @@ namespace MonoDevelop.Projects
public Task<T> BindTask<T> (Func<CancellationToken, Task<T>> f)
{
var t = f (disposeCancellation.Token);
- lock (activeTasks)
+ lock (activeTasks) {
+ if (disposeCancellation.IsCancellationRequested)
+ return Task.FromCanceled<T> (disposeCancellation.Token);
activeTasks.Add (t);
+ }
t.ContinueWith (tr => {
lock (activeTasks)
activeTasks.Remove (t);
@@ -118,8 +121,11 @@ namespace MonoDevelop.Projects
public Task BindTask (Func<CancellationToken, Task> f)
{
var t = f (disposeCancellation.Token);
- lock (activeTasks)
+ lock (activeTasks) {
+ if (disposeCancellation.IsCancellationRequested)
+ return Task.FromCanceled (disposeCancellation.Token);
activeTasks.Add (t);
+ }
t.ContinueWith (tr => {
lock (activeTasks)
activeTasks.Remove (t);
@@ -128,6 +134,22 @@ namespace MonoDevelop.Projects
}
/// <summary>
+ /// Gathers all the tasks for this WorkspaceObject and all children that need to finish before
+ /// this object can be disposed.
+ /// </summary>
+ internal void GetAllActiveTasksForDispose (List<Task> tasks)
+ {
+ lock (activeTasks) {
+ disposeCancellation.Cancel ();
+ tasks.AddRange (activeTasks);
+ }
+
+ foreach (var child in GetChildren ()) {
+ child.GetAllActiveTasksForDispose (tasks);
+ }
+ }
+
+ /// <summary>
/// Gets a value indicating whether this instance is shared.
/// </summary>
/// <remarks>Shared objects can only be modified in the main thread</remarks>
@@ -210,14 +232,10 @@ namespace MonoDevelop.Projects
Disposed = true;
- disposeCancellation.Cancel ();
-
- Task[] allTasks;
-
- lock (activeTasks)
- allTasks = activeTasks.ToArray ();
+ var allTasks = new List<Task> ();
+ GetAllActiveTasksForDispose (allTasks);
- if (allTasks.Length > 0)
+ if (allTasks.Count > 0)
Task.WhenAll (allTasks).ContinueWith (t => OnDispose (), TaskScheduler.FromCurrentSynchronizationContext ());
else
OnDispose ();
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs
index 60314a14b0..64150d0e48 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs
@@ -311,6 +311,7 @@ namespace MonoDevelop.Components.AtkCocoaHelper
}
static readonly IntPtr selSetAccessibilityServesAsTitleForUIElements_Handle = Selector.GetHandle ("setAccessibilityServesAsTitleForUIElements:");
+ static readonly IntPtr selAccessibilityServesAsTitleForUIElements_Handle = Selector.GetHandle ("accessibilityServesAsTitleForUIElements:");
public static void SetTitleFor (this Atk.Object o, params Atk.Object [] objects)
{
var nsa = GetNSAccessibilityElement (o);
@@ -348,7 +349,6 @@ namespace MonoDevelop.Components.AtkCocoaHelper
}
}
- static readonly IntPtr selAccessibilityServesAsTitleForUIElements_Handle = Selector.GetHandle ("setAccessibilityServesAsTitleForUIElements:");
public static void AddElementToTitle (this Atk.Object title, Atk.Object o)
{
var titleNsa = GetNSAccessibilityElement (title);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs
new file mode 100644
index 0000000000..802c392dbc
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs
@@ -0,0 +1,49 @@
+/*
+ * PropertyGrid.cs - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.comk>
+ * Eric Butler <eric@extremeboredom.net>
+ * Lluis Sanchez Gual <lluis@novell.com>
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ * Copyright (C) 2005 Eric Butler
+ * Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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;
+
+namespace MonoDevelop.Components
+{
+ public interface IPropertyGrid : IDisposable
+ {
+ bool IsEditing { get; }
+ void SetToolbarProvider (PropertyGrid.PropertyGrid.IToolbarProvider toolbarProvider);
+ void SetCurrentObject (object obj, object [] propertyProviders);
+ void BlankPad ();
+ void OnPadContentShown ();
+ void Populate (bool saveEditSession);
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs
index 3a23f70e0f..9d2330cbe2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs
@@ -51,7 +51,7 @@ namespace MonoDevelop.Components.PropertyGrid
{
[System.ComponentModel.Category("MonoDevelop.Components")]
[System.ComponentModel.ToolboxItem(true)]
- public class PropertyGrid: Gtk.VBox
+ public class PropertyGrid: Gtk.VBox, IPropertyGrid
{
object currentObject;
object[] propertyProviders;
@@ -288,11 +288,11 @@ namespace MonoDevelop.Components.PropertyGrid
QueueDraw ();
}
- internal bool IsEditing {
+ public bool IsEditing {
get { return tree.IsEditing; }
}
- internal void Populate (bool saveEditSession)
+ public void Populate (bool saveEditSession)
{
PropertyDescriptorCollection properties;
@@ -422,7 +422,14 @@ namespace MonoDevelop.Components.PropertyGrid
descTitle = descText = null;
UpdateHelp ();
}
-
+
+ public void BlankPad () => CurrentObject = null;
+
+ public void OnPadContentShown ()
+ {
+ //not implemented
+ }
+
public interface IToolbarProvider
{
void Insert (Widget w, int pos);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs
index cc7255ad44..f5c475a683 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs
@@ -34,6 +34,22 @@ namespace MonoDevelop.Components.Mac
{
static class NativeViewHelper
{
+ public static NSStackView CreateVerticalStackView (int spacing = 10, bool translatesAutoresizingMaskIntoConstraints = false) => new NSStackView () {
+ Orientation = NSUserInterfaceLayoutOrientation.Vertical,
+ Alignment = NSLayoutAttribute.Leading,
+ Spacing = spacing,
+ Distribution = NSStackViewDistribution.Fill,
+ TranslatesAutoresizingMaskIntoConstraints = translatesAutoresizingMaskIntoConstraints
+ };
+
+ public static NSStackView CreateHorizontalStackView (int spacing = 10) => new NSStackView () {
+ Orientation = NSUserInterfaceLayoutOrientation.Horizontal,
+ Alignment = NSLayoutAttribute.CenterY,
+ Spacing = spacing,
+ Distribution = NSStackViewDistribution.Fill,
+ TranslatesAutoresizingMaskIntoConstraints = false
+ };
+
public static NSAttributedString GetAttributedStringFromFormattedText (string formattedText)
{
formattedText = formattedText.Replace ("&amp;", "&");
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs
index 02d8da925c..e735c48d29 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs
@@ -110,7 +110,7 @@ namespace MonoDevelop.Ide.Commands
protected override void Run ()
{
using (var dlg = new NewFileDialog (null, null)) // new file seems to fail if I pass the project IdeApp.ProjectOperations.CurrentSelectedProject
- MessageService.ShowCustomDialog (dlg, IdeApp.Workbench.RootWindow);
+ MessageService.ShowCustomDialog (dlg, DesktopService.GetFocusedTopLevelWindow ());
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ViewCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ViewCommands.cs
index 4e5121d2b4..eb7b7d43d9 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ViewCommands.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ViewCommands.cs
@@ -222,6 +222,7 @@ namespace MonoDevelop.Ide.Commands
info.Text = IdeApp.Workbench.FullScreen
? GettextCatalog.GetString ("Exit Full Screen")
: GettextCatalog.GetString ("Enter Full Screen");
+ info.Enabled = IdeApp.Workbench.RootWindow.Visible && !WelcomePage.WelcomePageService.WelcomeWindowVisible;
} else if (Platform.IsWindows) {
//this is currently a no-op on Windows as it's broken, so hide it
info.Visible = info.Enabled = false;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/ProgressDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/ProgressDialog.cs
index 578ee869a2..63bec17924 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/ProgressDialog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/ProgressDialog.cs
@@ -57,8 +57,6 @@ namespace MonoDevelop.Ide.Gui.Dialogs
ActionArea.Hide ();
DefaultHeight = 5;
- TransientFor = parent.nativeWidget as Gtk.Window;
-
btnCancel.Visible = allowCancel;
expander.Visible = showDetails;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ProgressMonitoring/MessageDialogProgressMonitor.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ProgressMonitoring/MessageDialogProgressMonitor.cs
index 3e606b20c7..74e88fd5da 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ProgressMonitoring/MessageDialogProgressMonitor.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ProgressMonitoring/MessageDialogProgressMonitor.cs
@@ -57,12 +57,19 @@ namespace MonoDevelop.Ide.ProgressMonitoring
{
}
- public MessageDialogProgressMonitor (bool showProgress, bool allowCancel, bool showDetails, bool hideWhenDone): base (Runtime.MainSynchronizationContext)
+ public MessageDialogProgressMonitor (bool showProgress, bool allowCancel, bool showDetails, bool hideWhenDone)
+ : this (showProgress, allowCancel, showDetails, hideWhenDone, null)
+ {
+ }
+
+ public MessageDialogProgressMonitor (bool showProgress, bool allowCancel, bool showDetails, bool hideWhenDone, Components.Window parent)
+ : base (Runtime.MainSynchronizationContext)
{
if (showProgress) {
- dialog = new ProgressDialog (MessageService.RootWindow, allowCancel, showDetails);
+ var parentWindow = parent ?? DesktopService.GetFocusedTopLevelWindow ();
+ dialog = new ProgressDialog (parentWindow, allowCancel, showDetails);
dialog.Message = "";
- MessageService.PlaceDialog (dialog, MessageService.RootWindow);
+ MessageService.PlaceDialog (dialog, parentWindow);
dialog.Show ();
dialog.CancellationTokenSource = CancellationTokenSource;
DispatchService.RunPendingEvents ();
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs
index 1b1774908d..d60e6866f5 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs
@@ -75,7 +75,6 @@ namespace MonoDevelop.Ide.Projects
this.basePath = basePath;
BorderWidth = 6;
- TransientFor = IdeApp.Workbench.RootWindow;
HasSeparator = false;
InitializeComponents ();
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs
index 999d6d6164..ef203184d9 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs
@@ -1,4 +1,4 @@
-//
+//
// MonoDevelopWorkspace.MetadataReferenceHandler.cs
//
// Author:
@@ -92,9 +92,6 @@ namespace MonoDevelop.Ide.TypeSystem
if (!await AddMetadataAssemblyReferences (data))
return ImmutableArray<MonoDevelopMetadataReference>.Empty;
-
- if (!AddMetadataProjectReferences (data))
- return ImmutableArray<MonoDevelopMetadataReference>.Empty;
return data.Result.ToImmutableArray ();
}
@@ -112,6 +109,9 @@ namespace MonoDevelop.Ide.TypeSystem
try {
var referencedAssemblies = await data.Project.GetReferencedAssemblies (data.ConfigurationSelector, false).ConfigureAwait (false);
foreach (var file in referencedAssemblies) {
+ if (file.IsProjectReference)
+ continue;
+
if (data.Token.IsCancellationRequested)
return false;
@@ -132,34 +132,6 @@ namespace MonoDevelop.Ide.TypeSystem
}
}
- bool AddMetadataProjectReferences (AddMetadataReferencesData data)
- {
- try {
- var referencedProjects = data.Project.GetReferencedItems (data.ConfigurationSelector);
- foreach (var pr in referencedProjects) {
- if (data.Token.IsCancellationRequested)
- return false;
-
- if (!(pr is MonoDevelop.Projects.DotNetProject referencedProject) || !IdeApp.TypeSystemService.IsOutputTrackedProject (referencedProject))
- continue;
-
- var fileName = referencedProject.GetOutputFileName (data.ConfigurationSelector);
- if (!data.Visited.Add (fileName))
- continue;
-
- var metadataReference = manager.GetOrCreateMetadataReference (fileName, MetadataReferenceProperties.Assembly);
- if (metadataReference != null)
- data.Result.Add (metadataReference);
- }
- } catch (Exception e) {
- LoggingService.LogError ("Error while getting referenced assemblies", e);
- // TODO: Check whether this should return false, I retained compat for now.
- return true;
- }
-
- return true;
- }
-
async Task<ImmutableArray<ProjectReference>> CreateProjectReferences (MonoDevelop.Projects.Project p, CancellationToken token)
{
if (!(p is MonoDevelop.Projects.DotNetProject netProj))
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageCommands.cs
index 8ba73b2f08..d365140109 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageCommands.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageCommands.cs
@@ -47,6 +47,8 @@ namespace MonoDevelop.Ide.WelcomePage
protected override void Update (CommandInfo info)
{
info.Text = WelcomePageService.HasWindowImplementation ? GettextCatalog.GetString ("Start Window") : GettextCatalog.GetString ("Welcome Page");
+ info.Enabled = (WelcomePageService.HasWindowImplementation && !WelcomePageService.WelcomeWindowVisible)
+ || (!WelcomePageService.HasWindowImplementation && !WelcomePageService.WelcomePageVisible);
base.Update (info);
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
index 2e8725280a..6550abf5a3 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
@@ -3168,7 +3168,6 @@
<Compile Include="MonoDevelop.Ide.Gui\Document.cs" />
<Compile Include="MonoDevelop.Ide.Gui\Pad.cs" />
<Compile Include="MonoDevelop.Ide.Gui\Workbench.cs" />
- <Compile Include="MonoDevelop.Ide.Gui\StartupInfo.cs" />
<Compile Include="MonoDevelop.Ide.Gui\ProgressMonitors.cs" />
<Compile Include="MonoDevelop.Ide.TypeSystem\IMonoDevelopHostDocument.cs" />
<Compile Include="MonoDevelop.Ide.TypeSystem\MonoDevelopPersistentStorageLocationService.cs" />
@@ -4237,6 +4236,10 @@
<Compile Include="MonoDevelop.Ide.Projects\NewSolutionRunConfigurationDialog.cs" />
<Compile Include="MonoDevelop.Ide.TypeSystem\HackyWorkspaceFilesCache.cs" />
<Compile Include="MonoDevelop.Ide.Gui.Dialogs\NewFolderDialog.cs" />
+ <Compile Include="MonoDevelop.Components.PropertyGrid\IPropertyGrid.cs" />
+ <Compile Include="MonoDevelop.Ide\MonoDevelopOptions.cs" />
+ <Compile Include="MonoDevelop.Ide\AddinError.cs" />
+ <Compile Include="MonoDevelop.Ide.Extensions\StartupInfo.cs" />
</ItemGroup>
<ItemGroup>
<Data Include="options\DefaultEditingLayout.xml" />
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
index 3c9fc3d78d..b09ed7619e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
@@ -1,4 +1,4 @@
-//
+//
// IdeApp.cs
//
// Author:
@@ -53,6 +53,7 @@ using MonoDevelop.Ide.TextEditing;
using MonoDevelop.Ide.Navigation;
using MonoDevelop.Ide.Fonts;
using MonoDevelop.Ide.Composition;
+using System.Diagnostics;
namespace MonoDevelop.Ide
{
@@ -98,8 +99,23 @@ namespace MonoDevelop.Ide
});
}
}
- internal static void OnStartupCompleted ()
+
+ static TimeToCodeMetadata ttcMetadata;
+ static Stopwatch ttcStopwatch;
+ static long startupCompletedTicks;
+ static long ttcDuration = 3 * TimeSpan.TicksPerSecond; // Wait 3 seconds before ignoring TTC events
+
+ internal static void OnStartupCompleted (StartupMetadata startupMetadata, Stopwatch ttcTimer)
{
+ ttcMetadata = new TimeToCodeMetadata {
+ StartupTime = startupMetadata.CorrectedStartupTime
+ };
+ ttcMetadata.AddProperties (startupMetadata);
+
+ ttcStopwatch = ttcTimer;
+ startupCompletedTicks = ttcStopwatch.ElapsedTicks;
+ LoggingService.LogDebug ("TTC starting");
+
startupCompleted?.Invoke (null, EventArgs.Empty);
}
@@ -177,20 +193,6 @@ namespace MonoDevelop.Ide
}
}
- // This flag tells us whether or not the solution being loaded was from the file manager.
- static bool reportTimeToCode;
- static bool fmTimeoutExpired;
- public static bool ReportTimeToCode {
- get => reportTimeToCode && !fmTimeoutExpired;
- set {
- reportTimeToCode = value;
- if (fmTimeoutId > 0) {
- GLib.Source.Remove (fmTimeoutId);
- fmTimeoutId = 0;
- }
- }
- }
-
public static async Task Initialize (ProgressMonitor monitor)
{
// Already done in IdeSetup, but called again since unit tests don't use IdeSetup.
@@ -325,20 +327,45 @@ namespace MonoDevelop.Ide
Ide.IdeApp.Workbench.StatusBar.ShowWarning (e.Message);
}
- static readonly uint fmTimeoutMs = 2500;
- static uint fmTimeoutId;
- internal static void StartFMOpenTimer (Action timeCompletion)
+ internal static void TrackTimeToCode (TimeToCodeMetadata.DocumentType documentType)
{
- // We only track time to code if the reportTimeToCode flag is set within fmTimeoutMs from this method being called
- fmTimeoutId = GLib.Timeout.Add (fmTimeoutMs, () => FMOpenTimerExpired (timeCompletion));
+ LoggingService.LogDebug("Tracking TTC");
+ if (ttcStopwatch == null || timeToCodeSolutionTimer == null) {
+ LoggingService.LogDebug("Ignoring TTC");
+ return;
+ }
+
+ ttcStopwatch.Stop ();
+ timeToCodeSolutionTimer.Stop ();
+
+ if (ttcMetadata == null) {
+ timeToCodeSolutionTimer = null;
+ ttcStopwatch = null;
+ throw new Exception ("SendTimeToCode called before initialisation completed");
+ }
+
+ LoggingService.LogDebug ("Processing TTC");
+ ttcMetadata.SolutionLoadTime = timeToCodeSolutionTimer.ElapsedMilliseconds;
+
+ ttcMetadata.CorrectedDuration = ttcStopwatch.ElapsedMilliseconds;
+ ttcMetadata.Type = documentType;
+
+ Counters.TimeToCode.Inc ("SolutionLoaded", ttcMetadata);
+
+ timeToCodeSolutionTimer = null;
}
- static bool FMOpenTimerExpired (Action timeCompletion)
+ static Stopwatch timeToCodeSolutionTimer = new Stopwatch ();
+ internal static bool StartTimeToCodeLoadTimer ()
{
- fmTimeoutExpired = true;
- fmTimeoutId = 0;
- timeCompletion ();
- return false;
+ if (ttcStopwatch.ElapsedTicks - startupCompletedTicks > ttcDuration) {
+ LoggingService.LogDebug ($"Not starting TTC timer: {ttcStopwatch.ElapsedTicks - startupCompletedTicks}");
+ return false;
+ }
+ LoggingService.LogDebug ("Starting TTC timer");
+ timeToCodeSolutionTimer.Start ();
+
+ return true;
}
public static void BringToFront ()
@@ -356,10 +383,10 @@ namespace MonoDevelop.Ide
}
//this method is MIT/X11, 2009, Michael Hutchinson / (c) Novell
- internal static async void OpenFiles (IEnumerable<FileOpenInformation> files, OpenWorkspaceItemMetadata metadata)
+ internal static async Task<bool> OpenFiles (IEnumerable<FileOpenInformation> files, OpenWorkspaceItemMetadata metadata)
{
if (!files.Any ())
- return;
+ return false;
if (!IsInitialized) {
EventHandler onInit = null;
@@ -368,7 +395,7 @@ namespace MonoDevelop.Ide
OpenFiles (files, metadata);
};
Initialized += onInit;
- return;
+ return false;
}
var filteredFiles = new List<FileOpenInformation> ();
@@ -412,6 +439,8 @@ namespace MonoDevelop.Ide
}
Workbench.Present ();
+
+ return true;
}
static bool FileServiceErrorHandler (string message, Exception ex)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs
index 69fe4db2d7..b12343faf4 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs
@@ -282,7 +282,7 @@ namespace MonoDevelop.Ide
// XBC #33699
Counters.Initialization.Trace ("Initializing IdeApp");
- hideWelcomePage = startupInfo.HasFiles || IdeApp.Preferences.StartupBehaviour.Value != OnStartupBehaviour.ShowStartWindow;
+ hideWelcomePage = options.NoStartWindow || startupInfo.HasFiles || IdeApp.Preferences.StartupBehaviour.Value != OnStartupBehaviour.ShowStartWindow;
await IdeApp.Initialize (monitor);
sectionTimings ["AppInitialization"] = startupSectionTimer.ElapsedMilliseconds;
@@ -378,17 +378,6 @@ namespace MonoDevelop.Ide
startupTimer.Stop ();
startupSectionTimer.Stop ();
- // Need to start this timer because we don't know yet if we've been asked to open a solution from the file manager.
- timeToCodeTimer.Start ();
- ttcMetadata = new TimeToCodeMetadata {
- StartupTime = startupTimer.ElapsedMilliseconds
- };
-
- // Start this timer to limit the time to decide if the app was opened by a file manager
- IdeApp.StartFMOpenTimer (FMOpenTimerExpired);
- IdeApp.Workspace.FirstWorkspaceItemOpened += CompleteSolutionTimeToCode;
- IdeApp.Workbench.DocumentOpened += CompleteFileTimeToCode;
-
CreateStartupMetadata (startupInfo, sectionTimings);
GLib.Idle.Add (OnIdle);
@@ -402,17 +391,6 @@ namespace MonoDevelop.Ide
Runtime.RegisterServiceType<IShell, DefaultWorkbench> ();
}
- void FMOpenTimerExpired ()
- {
- IdeApp.Workspace.FirstWorkspaceItemOpened -= CompleteSolutionTimeToCode;
- IdeApp.Workbench.DocumentOpened -= CompleteFileTimeToCode;
-
- timeToCodeTimer.Stop ();
- timeToCodeTimer = null;
-
- ttcMetadata = null;
- }
-
/// <summary>
/// Resolves MSBuild 15.0 assemblies that are used by MonoDevelop.Ide and are included with Mono.
/// </summary>
@@ -481,49 +459,7 @@ namespace MonoDevelop.Ide
var startupMetadata = GetStartupMetadata (si, result, timings);
Counters.Startup.Inc (startupMetadata);
- if (ttcMetadata != null) {
- ttcMetadata.AddProperties (startupMetadata);
- }
-
- IdeApp.OnStartupCompleted ();
- }
-
- enum TimeToCodeFileType
- {
- Solution,
- Document
- }
-
- static void CompleteSolutionTimeToCode (object sender, EventArgs args)
- {
- CompleteTimeToCode (TimeToCodeMetadata.DocumentType.Solution);
- }
-
- static void CompleteFileTimeToCode (object sender, EventArgs args)
- {
- CompleteTimeToCode (TimeToCodeMetadata.DocumentType.File);
- }
-
- static void CompleteTimeToCode (TimeToCodeMetadata.DocumentType type)
- {
- IdeApp.Workspace.FirstWorkspaceItemOpened -= CompleteSolutionTimeToCode;
- IdeApp.Workbench.DocumentOpened -= CompleteFileTimeToCode;
-
- if (timeToCodeTimer == null) {
- return;
- }
-
- timeToCodeTimer.Stop ();
- ttcMetadata.SolutionLoadTime = timeToCodeTimer.ElapsedMilliseconds;
-
- ttcMetadata.CorrectedDuration = ttcMetadata.StartupTime + ttcMetadata.SolutionLoadTime;
- ttcMetadata.Type = type;
-
- if (IdeApp.ReportTimeToCode) {
- Counters.TimeToCode.Inc ("SolutionLoaded", ttcMetadata);
- IdeApp.ReportTimeToCode = false;
- }
- timeToCodeTimer = null;
+ IdeApp.OnStartupCompleted (startupMetadata, timeToCodeTimer);
}
static DateTime lastIdle;
@@ -776,6 +712,7 @@ namespace MonoDevelop.Ide
// set as a metadata property on the Counters.Startup counter.
startupTimer.Start ();
startupSectionTimer.Start ();
+ timeToCodeTimer.Start ();
var options = MonoDevelopOptions.Parse (args);
if (options.ShowHelp || options.Error != null)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs
index 125a1aa8e7..286cd56b87 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs
@@ -348,10 +348,16 @@ namespace MonoDevelop.Ide
Runtime.RunInMainThread (() => {
// If there is a native NSWindow model window running, we need
// to show the new dialog over that window.
- if (NSApplication.SharedApplication.ModalWindow != null)
- dialog.Shown += HandleShown;
- else
+ if (NSApplication.SharedApplication.ModalWindow != null || (parent.nativeWidget is NSWindow && dialog.Modal)) {
+ EventHandler shownHandler = null;
+ shownHandler = (s,e) => {
+ ShowCustomModalDialog (dialog, parent);
+ dialog.Shown -= shownHandler;
+ };
+ dialog.Shown += shownHandler;
+ } else {
PlaceDialog (dialog, parent);
+ }
}).Wait ();
#endif
@@ -359,7 +365,13 @@ namespace MonoDevelop.Ide
try {
Xwt.MessageDialog.RootWindow = Xwt.Toolkit.CurrentEngine.WrapWindow (dialog);
IdeApp.DisableIdleActions ();
- return GtkWorkarounds.RunDialogWithNotification (dialog);
+ int result = GtkWorkarounds.RunDialogWithNotification (dialog);
+ // Focus parent window once the dialog is ran, as focus gets lost
+ if (parent != null) {
+ DesktopService.FocusWindow (parent);
+ }
+
+ return result;
} finally {
Xwt.MessageDialog.RootWindow = initialRootWindow;
IdeApp.EnableIdleActions ();
@@ -367,11 +379,11 @@ namespace MonoDevelop.Ide
}
#if MAC
- static void HandleShown (object sender, EventArgs e)
+ static void ShowCustomModalDialog (Gtk.Window dialog, Window parent)
{
- var dialog = (Gtk.Window)sender;
- var nsdialog = GtkMacInterop.GetNSWindow (dialog);
+ CenterWindow (dialog, parent);
+ var nsdialog = GtkMacInterop.GetNSWindow (dialog);
// Make the GTK window modal WRT the current modal NSWindow
var s = NSApplication.SharedApplication.BeginModalSession (nsdialog);
@@ -381,7 +393,6 @@ namespace MonoDevelop.Ide
dialog.Unrealized -= unrealizer;
};
dialog.Unrealized += unrealizer;
- dialog.Shown -= HandleShown;
}
#endif
@@ -417,16 +428,16 @@ namespace MonoDevelop.Ide
if (nsParent == null || !nsParent.IsVisible) {
nsChild.Center ();
} else {
- int x = (int)(Math.Max (0, nsParent.Frame.Left + (nsParent.Frame.Width - nsChild.Frame.Width) / 2));
- int y = (int)(Math.Max (0, nsParent.Frame.Top + (nsParent.Frame.Height - nsChild.Frame.Height) / 2));
- nsChild.SetFrame (new CoreGraphics.CGRect (x, y, nsChild.Frame.Width, nsChild.Frame.Height), true);
+ int x = (int) Math.Max (0, nsParent.Frame.Left + (nsParent.Frame.Width - nsChild.Frame.Width) / 2);
+ int y = (int) Math.Max (0, nsParent.Frame.Top + (nsParent.Frame.Height - nsChild.Frame.Height) / 2);
+ nsChild.SetFrameOrigin (new CoreGraphics.CGPoint (x, y));
}
return;
}
#endif
if (gtkChild != null) {
- gtkChild.Child.Show ();
+ gtkChild.Show ();
int x, y;
gtkChild.GetSize (out var w, out var h);
if (gtkParent != null) {
@@ -438,9 +449,10 @@ namespace MonoDevelop.Ide
gtkChild.Move (x, y);
#if MAC
} else if (nsParent != null) {
- x = (int)(Math.Max (0, nsParent.Frame.Left + (nsParent.Frame.Width - w) / 2));
- y = (int)(Math.Max (0, nsParent.Frame.Top + (nsParent.Frame.Height - h) / 2));
- gtkChild.Move (x, y);
+ nsChild = GtkMacInterop.GetNSWindow (gtkChild);
+ x = (int) Math.Max (0, nsParent.Frame.Left + (nsParent.Frame.Width - w) / 2);
+ y = (int) Math.Max (0, nsParent.Frame.Top + (nsParent.Frame.Height - h) / 2);
+ nsChild.SetFrameOrigin (new CoreGraphics.CGPoint (x, y));
#endif
} else {
gtkChild.SetPosition (Gtk.WindowPosition.Center);
@@ -589,7 +601,6 @@ namespace MonoDevelop.Ide
Caption = caption,
Value = initialValue,
IsPassword = isPassword,
- TransientFor = parent ?? DesktopService.GetParentForModalWindow ()
};
if (dialog.Run ())
return dialog.Value;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs
index b3a54c6ba4..8291d85155 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs
@@ -47,6 +47,8 @@ namespace MonoDevelop.Ide
Mono.Options.OptionSet GetOptionSet ()
{
return new Mono.Options.OptionSet {
+ { "no-splash", "Do not display splash screen (deprecated).", s => {} },
+ { "no-start-window", "Do not display start window", s => NoStartWindow = true },
{ "ipc-tcp", "Use the Tcp channel for inter-process communication.", s => IpcTcp = true },
{ "new-window", "Do not open in an existing instance of " + BrandingService.ApplicationName, s => NewWindow = true },
{ "h|?|help", "Show help", s => ShowHelp = true },
@@ -84,6 +86,7 @@ namespace MonoDevelop.Ide
return opt;
}
+ public bool NoStartWindow { get; set; }
public bool IpcTcp { get; set; }
public bool NewWindow { get; set; }
public bool ShowHelp { get; set; }
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs
index b26cf6a7ba..cbc299d62f 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs
@@ -1951,7 +1951,7 @@ namespace MonoDevelop.Ide
ProgressMonitor monitor = null;
if (files.Length > 10) {
- monitor = new MessageDialogProgressMonitor (true);
+ monitor = new MessageDialogProgressMonitor (true, true, true, true, MessageService.RootWindow);
monitor.BeginTask (GettextCatalog.GetString("Adding files..."), files.Length);
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Services.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Services.cs
index 87f4b79ef3..4f8ff5739d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Services.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Services.cs
@@ -161,7 +161,8 @@ namespace MonoDevelop.Ide
{
public enum DocumentType {
Solution,
- File
+ File,
+ Unknown
};
public long CorrectedDuration {
diff --git a/main/tests/Ide.Tests/MonoDevelop.Ide.Tests.csproj b/main/tests/Ide.Tests/MonoDevelop.Ide.Tests.csproj
index d57f65f521..39f267ccb7 100644
--- a/main/tests/Ide.Tests/MonoDevelop.Ide.Tests.csproj
+++ b/main/tests/Ide.Tests/MonoDevelop.Ide.Tests.csproj
@@ -146,6 +146,7 @@
<Compile Include="MonoDevelop.Ide.TypeSystem\TypeSystemServiceTests.cs" />
<Compile Include="MonoDevelop.Ide.RoslynServices\MonoDevelopFrameworkAssemblyPathResolverFactoryTests.cs" />
<Compile Include="MonoDevelop.Ide.TypeSystem\MonoDevelopWorkspaceTests.cs" />
+ <Compile Include="MonoDevelop.Ide\BaseCredentialsProviderTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\core\MonoDevelop.Ide\MonoDevelop.Ide.csproj">
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core/BaseCredentialsProviderTests.cs b/main/tests/Ide.Tests/MonoDevelop.Ide/BaseCredentialsProviderTests.cs
index f9f9faac09..8529d0e63b 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core/BaseCredentialsProviderTests.cs
+++ b/main/tests/Ide.Tests/MonoDevelop.Ide/BaseCredentialsProviderTests.cs
@@ -26,11 +26,13 @@
using System;
using NUnit.Framework;
using System.IO;
-
-namespace MonoDevelop.Core
+using UnitTests;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.Ide
{
[TestFixture]
- public abstract class BaseCredentialsProviderTests
+ public abstract class BaseCredentialsProviderTests : IdeTestBase
{
static readonly string mockUser = "md_test_" + Guid.NewGuid ();
static readonly Uri mockUrl = new Uri ("ftp://" + Path.GetRandomFileName () + ".randomdomain");
diff --git a/main/tests/MacPlatform.Tests/CredentialsProviderTests.cs b/main/tests/MacPlatform.Tests/CredentialsProviderTests.cs
index 94c183927a..6362ac17aa 100644
--- a/main/tests/MacPlatform.Tests/CredentialsProviderTests.cs
+++ b/main/tests/MacPlatform.Tests/CredentialsProviderTests.cs
@@ -1,4 +1,4 @@
-//
+//
// CredentialsProviderTests.cs
//
// Author:
@@ -23,31 +23,15 @@
// 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 MonoDevelop.MacInterop;
+
+using AppKit;
using NUnit.Framework;
namespace MacPlatform.Tests
{
[TestFixture]
- public class CredentialsProviderTests : MonoDevelop.Core.BaseCredentialsProviderTests
+ public class CredentialsProviderTests : MonoDevelop.Ide.BaseCredentialsProviderTests
{
- static string TestKeyChain = "ThisIsMonoDevelopsPrivateKeyChainForTests";
-
- [TestFixtureSetUp]
- public void FixtureSetup ()
- {
- Keychain.TryDeleteKeychain (TestKeyChain);
- Keychain.CurrentKeychain = Keychain.CreateKeychain (TestKeyChain, "mypassword");
- }
-
- [TestFixtureTearDown]
- public void FixtureTeardown ()
- {
- Keychain.DeleteKeychain (Keychain.CurrentKeychain);
- Keychain.CurrentKeychain = IntPtr.Zero;
- }
-
protected override MonoDevelop.Core.IPasswordProvider GetPasswordProvider ()
{
return new MonoDevelop.MacIntegration.MacKeychainPasswordProvider ();
diff --git a/main/tests/MacPlatform.Tests/KeychainTests.cs b/main/tests/MacPlatform.Tests/KeychainTests.cs
index ceae41e60a..fa4093fc8e 100644
--- a/main/tests/MacPlatform.Tests/KeychainTests.cs
+++ b/main/tests/MacPlatform.Tests/KeychainTests.cs
@@ -25,35 +25,20 @@
// THE SOFTWARE.
using System;
+using MonoDevelop.Ide;
using MonoDevelop.MacInterop;
using NUnit.Framework;
-using System.IO;
-using System.Text;
namespace MacPlatform.Tests
{
[TestFixture]
- public class KeychainTests
+ public class KeychainTests : IdeTestBase
{
- const string TestKeyChain = "ThisIsMonoDevelopsPrivateKeyChainForTests";
const string password = "pa55word";
- [SetUp]
- public void Setup ()
- {
- Keychain.TryDeleteKeychain (TestKeyChain);
- Keychain.CurrentKeychain = Keychain.CreateKeychain (TestKeyChain, "mypassword");
- }
-
- [TearDown]
- public void Teardown ()
- {
- Keychain.DeleteKeychain (Keychain.CurrentKeychain);
- Keychain.CurrentKeychain = IntPtr.Zero;
- }
-
- const string site = "http://google.com";
- const string siteWithUser = "http://user@google.com";
+ const string testDomain = "test-monodevelop-mac-keychain.com";
+ const string site = "http://" + testDomain;
+ const string siteWithUser = "http://user@" + testDomain;
const string siteWithPath = site + "/path";
const string siteWithUserAndPath = siteWithUser + "/path";
@@ -97,50 +82,180 @@ namespace MacPlatform.Tests
}
}
+ [TestCase (site, null, null, null, Description = "No User, Password Only")]
+ [TestCase (site, "user", "user", "user", Description = "User unchanged, Password Only")]
+ [TestCase (site, null, "user2", "user2", Description = "Add User")]
+ [TestCase (site, "user", "user2", "user2", Description = "Update User and Password")]
+ [TestCase (siteWithPath, null, null, null, Description = "With Path, No User, Password Only")]
+ [TestCase (siteWithPath, "user", "user", "user", Description = "With Path, User unchanged, Password Only")]
+ [TestCase (siteWithPath, null, "user2", "user2", Description = "Add User")]
+ [TestCase (siteWithPath, "user", "user2", "user2", Description = "With Path, Update User and Password")]
+ [TestCase (siteWithUser, null, null, "user", Description = "Fixed User, Password Only")]
+ [TestCase (siteWithUser, "user", "user2", "user", Description = "Fixed User, User and Password")]
+ public void InternetPassword_AddUpdateRemove (string url, string user, string updateUser, string expectedUsername)
+ {
+ var uri = new Uri (url);
+ var updatePassword = password + "Update";
+
+ if (user != null) {
+ Keychain.AddInternetPassword (uri, user, password);
+ } else {
+ Keychain.AddInternetPassword (uri, password);
+ }
+
+ try {
+ var foundPassword = Keychain.FindInternetPassword (uri);
+ var passAndUser = Keychain.FindInternetUserNameAndPassword (uri);
+
+ Assert.AreEqual (password, foundPassword);
+ if (user != null)
+ Assert.AreEqual (user, passAndUser.Item1);
+ Assert.AreEqual (password, passAndUser.Item2);
+
+ if (updateUser != null) {
+ Keychain.AddInternetPassword (uri, updateUser, updatePassword);
+ } else {
+ Keychain.AddInternetPassword (uri, updatePassword);
+ }
+
+ foundPassword = Keychain.FindInternetPassword (uri);
+ passAndUser = Keychain.FindInternetUserNameAndPassword (uri);
+
+ Assert.AreEqual (updatePassword, foundPassword);
+ Assert.AreEqual (expectedUsername, passAndUser.Item1);
+ Assert.AreEqual (updatePassword, passAndUser.Item2);
+ } finally {
+ Keychain.RemoveInternetPassword (uri);
+ if (!string.IsNullOrEmpty (uri.UserInfo)) {
+ Keychain.RemoveInternetUserNameAndPassword (uri);
+ }
+
+ Assert.IsNull (Keychain.FindInternetPassword (uri));
+ Assert.IsNull (Keychain.FindInternetUserNameAndPassword (uri));
+ }
+ }
+
+ [TestCase (site, "", "path2")]
+ [TestCase (site, "path1", "path2")]
+ [TestCase (siteWithUser, "path1", "path2")]
+ public void InternetPassword_SameHostDifferentPath (string url, string path1, string path2)
+ {
+ var uri1 = new Uri (url + "/" + path1);
+ var uri2 = new Uri (url + "/" + path2);
+ var user1 = !string.IsNullOrEmpty (uri1.UserInfo) ? uri1.UserInfo : "user1";
+ var user2 = !string.IsNullOrEmpty (uri2.UserInfo) ? uri2.UserInfo : "user2";
+ var password1 = password + "1";
+ var password2 = password + "2";
+
+ if (!string.IsNullOrEmpty (uri1.UserInfo))
+ Keychain.AddInternetPassword (uri1, password1);
+ else
+ Keychain.AddInternetPassword (uri1, user1, password1);
+
+ if (!string.IsNullOrEmpty (uri2.UserInfo))
+ Keychain.AddInternetPassword (uri2, password2);
+ else
+ Keychain.AddInternetPassword (uri2, user2, password2);
+
+ try {
+ var foundPassword1 = Keychain.FindInternetPassword (uri1);
+ var foundPasswordAndUser1 = Keychain.FindInternetUserNameAndPassword (uri1);
+ var foundPassword2 = Keychain.FindInternetPassword (uri2);
+ var foundPasswordAndUser2 = Keychain.FindInternetUserNameAndPassword (uri2);
+
+ Assert.AreEqual (password1, foundPassword1);
+ Assert.AreEqual (user1, foundPasswordAndUser1.Item1);
+ Assert.AreEqual (password1, foundPasswordAndUser1.Item2);
+ Assert.AreEqual (password2, foundPassword2);
+ Assert.AreEqual (user2, foundPasswordAndUser2.Item1);
+ Assert.AreEqual (password2, foundPasswordAndUser2.Item2);
+ } finally {
+ Keychain.RemoveInternetPassword (uri1);
+ Keychain.RemoveInternetPassword (uri2);
+ if (!string.IsNullOrEmpty (uri1.UserInfo)) {
+ Keychain.RemoveInternetUserNameAndPassword (uri1);
+ }
+ if (!string.IsNullOrEmpty (uri2.UserInfo)) {
+ Keychain.RemoveInternetUserNameAndPassword (uri2);
+ }
+
+ Assert.IsNull (Keychain.FindInternetPassword (uri1));
+ Assert.IsNull (Keychain.FindInternetUserNameAndPassword (uri1));
+
+ Assert.IsNull (Keychain.FindInternetPassword (uri2));
+ Assert.IsNull (Keychain.FindInternetUserNameAndPassword (uri2));
+ }
+ }
+
[Test]
public void InternetPassword_Remove ()
{
- var uriBase = new Uri ("http://google.com");
- var uri1 = new Uri ("http://user1@google.com");
- var uri2 = new Uri ("http://user2@google.com");
- var uri3 = new Uri ("http://user2@google.com");
-
- Keychain.AddInternetPassword (uriBase, password);
- Keychain.AddInternetPassword (uri1, "user1", password);
- Keychain.AddInternetPassword (uri2, "user2", password);
- Keychain.AddInternetPassword (uri3, "user3", password);
-
- AssertKeychain (uriBase, null, password, password);
- AssertKeychain (uri1, null, password, password);
- AssertKeychain (uri2, null, password, password);
- AssertKeychain (uri3, null, password, password);
-
- // We removed the password for null user
- Keychain.RemoveInternetPassword (uriBase);
- AssertKeychain (uriBase, "user1", password, password);
- AssertKeychain (uri1, "user1", password, password);
- AssertKeychain (uri2, "user1", password, password);
- AssertKeychain (uri3, "user1", password, password);
-
- // We removed user and pass for user1.
- Keychain.RemoveInternetUserNameAndPassword (uri1);
- AssertKeychain (uriBase, "user2", password, password);
- AssertKeychain (uri1, "user2", password, null);
- AssertKeychain (uri2, "user2", password, password);
- AssertKeychain (uri3, "user2", password, password);
-
- // We removed user and pass for non-user
- Keychain.RemoveInternetPassword (uri2);
- AssertKeychain (uriBase, "user3", password, password);
- AssertKeychain (uri1, "user3", password, null);
- AssertKeychain (uri2, "user3", password, null);
- AssertKeychain (uri2, "user3", password, null);
-
- Keychain.RemoveInternetUserNameAndPassword (uri3);
- AssertKeychain (uriBase, null, null, null);
- AssertKeychain (uri1, null, null, null);
- AssertKeychain (uri2, null, null, null);
- AssertKeychain (uri2, null, null, null);
+ string passwordNoUser = password + "nouser";
+
+ var uriBase = new Uri ("http://" + testDomain);
+ var uri1 = new Uri ("http://user1@" + testDomain);
+ var uri2 = new Uri ("http://user2@" + testDomain);
+ var uri3 = new Uri ("http://" + testDomain + "/path");
+
+ try {
+ Keychain.AddInternetPassword (uriBase, passwordNoUser);
+ Keychain.AddInternetPassword (uri1, password);
+ Keychain.AddInternetPassword (uri2, password);
+ Keychain.AddInternetPassword (uri3, "user2", password);
+
+ AssertKeychain (uriBase, null, passwordNoUser, passwordNoUser);
+ AssertKeychain (uri1, "user1", password, password);
+ AssertKeychain (uri2, "user2", password, password);
+ AssertKeychain (uri3, "user2", password, password);
+
+ Keychain.RemoveInternetPassword (uriBase);
+ // We removed the password for the entry without user
+ // The next best match for uriBase should be "user1" from uri1
+ AssertKeychain (uriBase, "user1", password, password);
+ AssertKeychain (uri1, "user1", password, password);
+ AssertKeychain (uri2, "user2", password, password);
+ AssertKeychain (uri3, "user2", password, password);
+
+ Keychain.RemoveInternetUserNameAndPassword (uri1);
+ // We removed user and pass for user1.
+ // The next best match for uriBase "user2" from uri2 now
+ AssertKeychain (uriBase, "user2", password, password);
+ // uri1 has no other match, because the user name is specified in the url
+ AssertKeychain (uri1, null, null, null);
+ AssertKeychain (uri2, "user2", password, password);
+ AssertKeychain (uri3, "user2", password, password);
+
+ Keychain.RemoveInternetUserNameAndPassword (uri2);
+ AssertKeychain (uriBase, null, null, null);
+ AssertKeychain (uri1, null, null, null);
+ AssertKeychain (uri2, null, null, null);
+ AssertKeychain (uri3, "user2", password, password);
+
+ Keychain.RemoveInternetUserNameAndPassword (uri3);
+ // We removed all entries
+ AssertKeychain (uriBase, null, null, null);
+ AssertKeychain (uri1, null, null, null);
+ AssertKeychain (uri2, null, null, null);
+ AssertKeychain (uri3, null, null, null);
+ } finally {
+ Keychain.RemoveInternetPassword (uriBase);
+ Keychain.RemoveInternetPassword (uri1);
+ Keychain.RemoveInternetPassword (uri2);
+ Keychain.RemoveInternetPassword (uri3);
+ Keychain.RemoveInternetUserNameAndPassword (uriBase);
+ Keychain.RemoveInternetUserNameAndPassword (uri1);
+ Keychain.RemoveInternetUserNameAndPassword (uri2);
+ Keychain.RemoveInternetUserNameAndPassword (uri3);
+
+ Assert.IsNull (Keychain.FindInternetPassword (uriBase));
+ Assert.IsNull (Keychain.FindInternetUserNameAndPassword (uriBase));
+ Assert.IsNull (Keychain.FindInternetPassword (uri1));
+ Assert.IsNull (Keychain.FindInternetUserNameAndPassword (uri1));
+ Assert.IsNull (Keychain.FindInternetPassword (uri2));
+ Assert.IsNull (Keychain.FindInternetUserNameAndPassword (uri2));
+ Assert.IsNull (Keychain.FindInternetPassword (uri3));
+ Assert.IsNull (Keychain.FindInternetUserNameAndPassword (uri3));
+ }
void AssertKeychain (Uri uri, string expectedUser, string expectedUserPassword, string expectedPassword)
{
@@ -157,25 +272,5 @@ namespace MacPlatform.Tests
Assert.AreEqual (expectedPassword, foundPassword);
}
}
-
- [Test]
- public void ToNullTerminatedUtf8IsNullTerminated ()
- {
- var str = "This is a test string";
-
- var bytes = Encoding.UTF8.GetBytes (str);
- var bytesWithNullTerm = str.ToNullTerminatedUtf8 ();
-
- Assert.AreEqual (bytes.Length + 1, bytesWithNullTerm.Length);
- Assert.AreEqual (0, bytesWithNullTerm [bytesWithNullTerm.Length - 1]);
-
- // UTF8Encoding does not handle null terminated strings, so do the check like this.
- Assert.AreEqual (str + char.MinValue, Encoding.UTF8.GetString (bytesWithNullTerm));
-
- const int offset = 2;
- var bytesWithNullTermOffset = str.ToNullTerminatedUtf8 (offset);
- Assert.AreEqual (str.Substring (offset) + char.MinValue, Encoding.UTF8.GetString (bytesWithNullTermOffset));
- }
}
-}
-
+} \ No newline at end of file
diff --git a/main/tests/MacPlatform.Tests/MacPlatform.Tests.csproj b/main/tests/MacPlatform.Tests/MacPlatform.Tests.csproj
index 4a47a350a5..ceba7a8f86 100644
--- a/main/tests/MacPlatform.Tests/MacPlatform.Tests.csproj
+++ b/main/tests/MacPlatform.Tests/MacPlatform.Tests.csproj
@@ -65,6 +65,11 @@
<Name>IdeUnitTests</Name>
<Private>False</Private>
</ProjectReference>
+ <ProjectReference Include="..\Ide.Tests\MonoDevelop.Ide.Tests.csproj">
+ <Project>{73D4CC8B-BAB9-4A29-841B-F25C6311F067}</Project>
+ <Name>MonoDevelop.Ide.Tests</Name>
+ <Private>False</Private>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
index 8cec1f0621..98ea1e3b4c 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
@@ -83,7 +83,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="MonoDevelop.Core\BacktrackingStringMatcherTests.cs" />
- <Compile Include="MonoDevelop.Core\BaseCredentialsProviderTests.cs" />
<Compile Include="MonoDevelop.Core\CoreExtensionsTests.cs" />
<Compile Include="MonoDevelop.Core\FilePathTests.cs" />
<Compile Include="MonoDevelop.Core\FileServiceTests.cs" />
@@ -153,6 +152,7 @@
<Compile Include="MonoDevelop.Core\SdkResolverTests.cs" />
<Compile Include="MonoDevelop.Core\FileServiceEventQueueTests.cs" />
<Compile Include="MonoDevelop.Core\FileServiceEventStateMachineTests.cs" />
+ <Compile Include="MonoDevelop.Projects\AsyncCriticalSectionTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\core\MonoDevelop.Core\MonoDevelop.Core.csproj">
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs
new file mode 100644
index 0000000000..3406f814e1
--- /dev/null
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/AsyncCriticalSectionTests.cs
@@ -0,0 +1,78 @@
+//
+// AsyncCriticalSectionTests.cs
+//
+// Author:
+// Matt Ward <matt.ward@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// 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.Threading;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace MonoDevelop.Projects
+{
+ [TestFixture]
+ public class AsyncCriticalSectionTests
+ {
+ AsyncCriticalSection referenceCacheLock;
+ ManualResetEvent unlockEvent;
+ ManualResetEvent doneEvent;
+ const int maxLoadProjectCalls = 10000;
+
+ [Test]
+ public void StackOverflowTest ()
+ {
+ referenceCacheLock = new AsyncCriticalSection ();
+ unlockEvent = new ManualResetEvent (false);
+ doneEvent = new ManualResetEvent (false);
+
+ for (int i = 0; i < maxLoadProjectCalls; ++i) {
+ Run (i);
+ }
+
+ Thread.Sleep (500);
+
+ unlockEvent.Set ();
+ bool result = doneEvent.WaitOne (5000);
+ if (!result)
+ Assert.Fail ("Done event not fired.");
+ }
+
+ void Run (int i)
+ {
+ Task.Run (async () => {
+ await LoadProject (i);
+ });
+ }
+
+ async Task LoadProject (int i)
+ {
+ using (await referenceCacheLock.EnterAsync ().ConfigureAwait (false)) {
+ unlockEvent.WaitOne ();
+
+ if (i == maxLoadProjectCalls - 1)
+ doneEvent.Set ();
+ }
+ }
+ }
+}
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SharedAssetsProjectTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SharedAssetsProjectTests.cs
index 129a08b668..f738e46ea8 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SharedAssetsProjectTests.cs
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SharedAssetsProjectTests.cs
@@ -23,6 +23,8 @@
// 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 NUnit.Framework;
using System.Linq;
using UnitTests;
@@ -547,6 +549,36 @@ namespace MonoDevelop.Projects
sol.Dispose ();
}
+
+ /// <summary>
+ /// Ensures that when the SharedAssetsProject has no language defined a null reference exception is not
+ /// thrown on saving.
+ /// </summary>
+ [Test]
+ public async Task SaveSharedProjectMissingImports ()
+ {
+ string projectFile = Util.GetSampleProject ("SharedProjectMissingImport", "Shared.shproj");
+ using (var project = await Services.ProjectService.ReadSolutionItem (Util.GetMonitor (), projectFile)) {
+ await project.SaveAsync (Util.GetMonitor ());
+ }
+ }
+
+ /// <summary>
+ /// If a solution file is edited by hand and a shared assets project type GUID is being used then
+ /// a SharedAssetsProject would be used. Since this is an invalid solution file the SharedAssetsProject
+ /// will throw an exception indicating a problem.
+ /// </summary>
+ [Test]
+ public async Task LoadSolutionWithSharedAssetsProjectTypeGuidUsedForCSharpProject ()
+ {
+ string solutionFile = Util.GetSampleProject ("SharedProjectTypeGuidMismatch", "SharedProjectTypeGuidMismatch.sln");
+ using (var solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFile)) {
+ var project = solution.Items [0] as UnknownSolutionItem;
+
+ Assert.IsNotNull (project);
+ Assert.That (project.LoadError, Contains.Substring ("Project Library is being loaded as a Shared Assets project but has a different file extension"));
+ }
+ }
}
}
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SolutionTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SolutionTests.cs
index efc321b272..fb969dc51c 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SolutionTests.cs
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/SolutionTests.cs
@@ -1010,6 +1010,51 @@ namespace MonoDevelop.Projects
Runtime.Preferences.SkipBuildingUnmodifiedProjects.Set (oldPrefSkipUnmodified);
}
}
+
+ [Test]
+ public async Task SolutionDisposed_ActiveProjectTasks_MSBuildEngineManagerNotDisposedUntilProjectTasksCompleted ()
+ {
+ var en = new CustomSolutionItemNode<TestProjectExtension> ();
+ WorkspaceObject.RegisterCustomExtension (en);
+ try {
+ string solFile = Util.GetSampleProject ("console-project", "ConsoleProject.sln");
+ var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solFile);
+
+ var p = (DotNetProject)sol.Items [0];
+ var msbuildProject = p.MSBuildProject;
+
+ var ext = p.GetFlavor<TestProjectExtension> ();
+ var task = ext.RunTestTask ();
+ sol.Dispose ();
+
+ // Should not throw. Evaluating requires the MSBuildEngineManager to not be disposed.
+ msbuildProject.Evaluate ();
+
+ try {
+ // Ensure that BindTask cannot be used after Solution has been disposed but
+ // project has not yet been disposed.
+ await p.BindTask (ct => Task.CompletedTask);
+ Assert.Fail ("Should not reach here.");
+ } catch (TaskCanceledException) {
+ // Expected
+ }
+
+ try {
+ // Ensure that BindTask<T> cannot be used after Solution has been disposed but
+ // project has not yet been disposed.
+ await p.BindTask (ct => Task.FromResult (true));
+ Assert.Fail ("Should not reach here.");
+ } catch (TaskCanceledException) {
+ // Expected
+ }
+
+ ext.TaskCompletionSource.TrySetResult (true);
+
+ await task;
+ } finally {
+ WorkspaceObject.UnregisterCustomExtension (en);
+ }
+ }
}
class SomeItem: SolutionItem
@@ -1105,4 +1150,16 @@ namespace MonoDevelop.Projects
return base.OnBuild (monitor, configuration, operationContext);
}
}
+
+ class TestProjectExtension : DotNetProjectExtension
+ {
+ public TaskCompletionSource<bool> TaskCompletionSource = new TaskCompletionSource<bool> ();
+
+ public Task RunTestTask ()
+ {
+ return Project.BindTask (async (ct) => {
+ await TaskCompletionSource.Task;
+ });
+ }
+ }
}
diff --git a/main/tests/WindowsPlatform.Tests/CredentialsProviderTests.cs b/main/tests/WindowsPlatform.Tests/CredentialsProviderTests.cs
index 032eadf8b1..8a6f211adf 100644
--- a/main/tests/WindowsPlatform.Tests/CredentialsProviderTests.cs
+++ b/main/tests/WindowsPlatform.Tests/CredentialsProviderTests.cs
@@ -30,7 +30,7 @@ using System.IO;
namespace WindowsPlatform.Tests
{
[TestFixture]
- public class CredentialsProviderTests : MonoDevelop.Core.BaseCredentialsProviderTests
+ public class CredentialsProviderTests : MonoDevelop.Ide.BaseCredentialsProviderTests
{
protected override MonoDevelop.Core.IPasswordProvider GetPasswordProvider ()
{
diff --git a/main/tests/WindowsPlatform.Tests/WindowsPlatform.Tests.csproj b/main/tests/WindowsPlatform.Tests/WindowsPlatform.Tests.csproj
index bd4dbc0b77..eea98685ef 100644
--- a/main/tests/WindowsPlatform.Tests/WindowsPlatform.Tests.csproj
+++ b/main/tests/WindowsPlatform.Tests/WindowsPlatform.Tests.csproj
@@ -28,10 +28,10 @@
<Project>{D12F0F7B-8DE3-43EC-BA49-41052D065A9B}</Project>
<Name>GuiUnit_NET_4_5</Name>
</ProjectReference>
- <ProjectReference Include="..\MonoDevelop.Core.Tests\MonoDevelop.Core.Tests.csproj">
- <Project>{fda43caa-1c2a-4593-8601-3e2ee06d9e03}</Project>
- <Name>MonoDevelop.Core.Tests</Name>
- </ProjectReference>
+ <ProjectReference Include="..\IdeUnitTests\IdeUnitTests.csproj">
+ <Project>{F7B2B155-7CF4-42C4-B5AF-63C0667D2E4F}</Project>
+ <Name>IdeUnitTests</Name>
+ </ProjectReference>
<ProjectReference Include="..\UnitTests\UnitTests.csproj">
<Project>{1497D0A8-AFF1-4938-BC22-BE79B358BA5B}</Project>
<Name>UnitTests</Name>
@@ -41,6 +41,11 @@
<Name>MonoDevelop.Core</Name>
<Private>False</Private>
</ProjectReference>
+ <ProjectReference Include="..\Ide.Tests\MonoDevelop.Ide.Tests.csproj">
+ <Project>{73D4CC8B-BAB9-4A29-841B-F25C6311F067}</Project>
+ <Name>MonoDevelop.Ide.Tests</Name>
+ <Private>False</Private>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
diff --git a/main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.csproj b/main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.csproj
new file mode 100644
index 0000000000..6c1cfcf8f3
--- /dev/null
+++ b/main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.csproj
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{7F63CBE6-2FE7-47A7-8930-EA078DA05062}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AssemblyName>RestoreStylePackageReference</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.sln b/main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.sln
new file mode 100644
index 0000000000..473e43ef36
--- /dev/null
+++ b/main/tests/test-projects/RestoreStylePackageReference/RestoreStylePackageReference.sln
@@ -0,0 +1,19 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestoreStylePackageReference", "RestoreStylePackageReference.csproj", "{7F63CBE6-2FE7-47A7-8930-EA078DA05062}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7F63CBE6-2FE7-47A7-8930-EA078DA05062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F63CBE6-2FE7-47A7-8930-EA078DA05062}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F63CBE6-2FE7-47A7-8930-EA078DA05062}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F63CBE6-2FE7-47A7-8930-EA078DA05062}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ EndGlobalSection
+EndGlobal
diff --git a/main/tests/test-projects/SharedProjectMissingImport/Shared.shproj b/main/tests/test-projects/SharedProjectMissingImport/Shared.shproj
new file mode 100644
index 0000000000..5aa2b8aedf
--- /dev/null
+++ b/main/tests/test-projects/SharedProjectMissingImport/Shared.shproj
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{551C9391-1E8F-47D3-9C80-6AE04DE1AEE3}</ProjectGuid>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/main/tests/test-projects/SharedProjectTypeGuidMismatch/Library.csproj b/main/tests/test-projects/SharedProjectTypeGuidMismatch/Library.csproj
new file mode 100644
index 0000000000..f4477bbd56
--- /dev/null
+++ b/main/tests/test-projects/SharedProjectTypeGuidMismatch/Library.csproj
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{551C9391-1E8F-47D3-9C80-6AE04DE1AEE3}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AssemblyName>library1</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/main/tests/test-projects/SharedProjectTypeGuidMismatch/SharedProjectTypeGuidMismatch.sln b/main/tests/test-projects/SharedProjectTypeGuidMismatch/SharedProjectTypeGuidMismatch.sln
new file mode 100644
index 0000000000..b324b6fb65
--- /dev/null
+++ b/main/tests/test-projects/SharedProjectTypeGuidMismatch/SharedProjectTypeGuidMismatch.sln
@@ -0,0 +1,15 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Library", "Library.csproj", "{551C9391-1E8F-47D3-9C80-6AE04DE1AEE3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ EndGlobalSection
+EndGlobal