mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-18 06:21:41 +08:00
Compare commits
139 Commits
v1.76Alpha
...
v1.76.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ab221e5a8 | ||
|
|
21e51c8455 | ||
|
|
3234896caf | ||
|
|
b00dd1c5f5 | ||
|
|
992a3f9d1c | ||
|
|
d1a7a37909 | ||
|
|
1c12b52ada | ||
|
|
722fe40899 | ||
|
|
b2e7ebf43d | ||
|
|
3ed8e768aa | ||
|
|
d362691389 | ||
|
|
4b7c54d5b5 | ||
|
|
ec80a5aa70 | ||
|
|
0c95f178ca | ||
|
|
e0405b15df | ||
|
|
e029f30acf | ||
|
|
44ed836b7c | ||
|
|
00401201d1 | ||
|
|
20f46bea61 | ||
|
|
a5d22d287c | ||
|
|
793095900b | ||
|
|
f10e54e47b | ||
|
|
704e0c1dc1 | ||
|
|
0c79a9acde | ||
|
|
ebfc2715e7 | ||
|
|
b0dbc9dc18 | ||
|
|
507cdf75a5 | ||
|
|
8f8492b0be | ||
|
|
457e715188 | ||
|
|
1724521ebf | ||
|
|
b0fb3596aa | ||
|
|
fb228d72b1 | ||
|
|
916361a3be | ||
|
|
408c40f699 | ||
|
|
4173f6d775 | ||
|
|
e6f3c22064 | ||
|
|
a013518eac | ||
|
|
9c88cacb3d | ||
|
|
d49bf04b15 | ||
|
|
1dbd5dc5bc | ||
|
|
c103706a54 | ||
|
|
b0a027df52 | ||
|
|
868641378a | ||
|
|
11baae3107 | ||
|
|
ed8125042e | ||
|
|
25b2655d0f | ||
|
|
145a264154 | ||
|
|
3e33170ae0 | ||
|
|
d18bf68f0e | ||
|
|
368917e108 | ||
|
|
cdea4c3911 | ||
|
|
b4b9b55bbf | ||
|
|
6092c63df4 | ||
|
|
fda5132184 | ||
|
|
6a9fb25a18 | ||
|
|
18d7344690 | ||
|
|
ba50cf20a0 | ||
|
|
7bd6e126e2 | ||
|
|
f7521c81d5 | ||
|
|
f483a2dc2f | ||
|
|
9769d5af06 | ||
|
|
0a2dc3563e | ||
|
|
e9f0157b2b | ||
|
|
e8e566fcdd | ||
|
|
72b7d22cef | ||
|
|
f79da476fd | ||
|
|
ef31b7844c | ||
|
|
f1ed1bf115 | ||
|
|
23ea028965 | ||
|
|
42046a614f | ||
|
|
36055f56e6 | ||
|
|
b693cb30fc | ||
|
|
20377d4ff5 | ||
|
|
570d732b0e | ||
|
|
d9d2b1de70 | ||
|
|
0a7eaaf36f | ||
|
|
36dd3e496d | ||
|
|
83fd914d7b | ||
|
|
281c6b13fa | ||
|
|
00b7b1221c | ||
|
|
56cbf0ff3f | ||
|
|
f852a4d341 | ||
|
|
7c8c7d482a | ||
|
|
9e95ae2cb0 | ||
|
|
0d2d935f17 | ||
|
|
eeb320a825 | ||
|
|
9452d4dbe3 | ||
|
|
03d2387cdd | ||
|
|
61b325ccb9 | ||
|
|
e57de9a4de | ||
|
|
96946f3a1e | ||
|
|
8cd6fb7ae2 | ||
|
|
a5afa90790 | ||
|
|
f634eb8d37 | ||
|
|
694b61a67b | ||
|
|
88f0d00a15 | ||
|
|
e31088fd2e | ||
|
|
1d7bb63710 | ||
|
|
af1ed5349f | ||
|
|
9dcf71dc31 | ||
|
|
8bf9af0ed8 | ||
|
|
aecfad5871 | ||
|
|
3edd155898 | ||
|
|
2c419c0b2e | ||
|
|
2fb67e7042 | ||
|
|
29483b2625 | ||
|
|
7fc59e79f3 | ||
|
|
79b3e21148 | ||
|
|
ee91117010 | ||
|
|
0548037ff3 | ||
|
|
46002632bb | ||
|
|
9659ac1611 | ||
|
|
bbc497e68d | ||
|
|
d7ec7574ad | ||
|
|
2f476d9e61 | ||
|
|
c74f37f0de | ||
|
|
d27a62cbfc | ||
|
|
8029e491a3 | ||
|
|
fe56268421 | ||
|
|
2db6fabbe9 | ||
|
|
035e89801a | ||
|
|
3bdcf655fd | ||
|
|
284755f298 | ||
|
|
ad5eed96e7 | ||
|
|
431c830ea0 | ||
|
|
da047427a5 | ||
|
|
69da1dca5f | ||
|
|
cc61501f63 | ||
|
|
4ced2d3392 | ||
|
|
7c72bfdf6b | ||
|
|
b8878e1458 | ||
|
|
abd40cec1b | ||
|
|
cc18da4f28 | ||
|
|
1a39039162 | ||
|
|
cf9dd72ea5 | ||
|
|
b7cdf81665 | ||
|
|
8497a05fd1 | ||
|
|
7db4eec45c | ||
|
|
cd822b545a |
@@ -1,3 +1,83 @@
|
||||
1.76.11 (2018-10-18):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1139: Feature "Reconnect to previously opened sessions" not working
|
||||
#1136: Putty window not maximized
|
||||
|
||||
|
||||
1.76.10 (2018-10-07):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1124: Enabling themes causes an exception
|
||||
|
||||
|
||||
1.76.9 (2018-10-07):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1117: Duplicate panel created when "Reconnect on Startup" and "Create Empty Panel" settings enabled
|
||||
#1115: Exception when changing from xml data storage to SQL
|
||||
#1110: Pressing Delete button during connection rename attempts to delete the connection instead of the text
|
||||
#1106: Inheritance does not work when parent has C# default type set
|
||||
#1092: Invalid Cast Exceptions loading default connectioninfo
|
||||
#1091: Minor themeing issues
|
||||
#853: Added some additional safety checks and logging to help address RDP crashes
|
||||
|
||||
|
||||
1.76.8 (2018-08-25):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1088: Delete and Launch buttons are not disabled when last external tool deleted
|
||||
#1087: 'Save connections after every edit' setting not honored
|
||||
#1082: Connections not given GUID if Id is empty in connection xml
|
||||
|
||||
|
||||
1.76.7 (2018-08-22):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1076: Wrong object selected when duplicating connection then switching between properties and inheritance in config window
|
||||
#1068: Fixed some toolbar positioning bugs
|
||||
|
||||
|
||||
1.76.6 (2018-08-03):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1062: Entering correct password when starting app does not load connections file
|
||||
|
||||
1.76.5 (2018-08-02):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1057: Hitting F2 with no connection node selected caused unhandled exception
|
||||
#1052: 'Switch to notification panel' feature does not always switch
|
||||
#1051: Tooltips always displayed regardless of 'Show description tooltips in connection tree' setting
|
||||
#1050: Config window retains access to previously selected node after loading new connections file
|
||||
#1045: Config window shows several incorrect properties for HTTPS connections
|
||||
#1040: Canceling "select panel" form does not cancel
|
||||
#1039: Set default theme when themes disabled
|
||||
#1038: Unable to add connection with active filter
|
||||
#1036: Exception when themes are active and options page closed on Connections then reopened
|
||||
#1034: Connection context menu not being translated
|
||||
#1030: Exception thrown if importing from port scan and no tree node is selected
|
||||
#1020: BackupFileKeepCount setting not limiting backup file count
|
||||
#1004: Duplicating root or PuTTy node through hotkey causes unhandled exception
|
||||
#1002: Disabling filtering without clearing keyword leaves filtered state
|
||||
#1001: Connection tree context menu hotkeys stop working and disappear in some cases
|
||||
#999: Some hotkeys stop working if File menu was called when PuTTy Saved Sessions was selected
|
||||
#998: Can sometimes add connection under PuTTY Sessions node
|
||||
#991: Error when deleting host in filtered view
|
||||
#971: Portable Settings now apply to any machine they are used on
|
||||
#961: Connections file overwritten if correct decryption password not provided
|
||||
#893: Removed unneeded files from build/package
|
||||
#868: if statement returned the same value
|
||||
#762: Increased button size to fit locaized text
|
||||
|
||||
|
||||
1.76.4 Alpha 6 (2018-06-03):
|
||||
|
||||
Features/Enhancements:
|
||||
|
||||
@@ -24,6 +24,7 @@ github.com/pfjason
|
||||
github.com/sirLoaf
|
||||
github.com/Fyers
|
||||
Vladimir Semenov (github.com/sli-pro)
|
||||
Stephan (github.com/st-schuler)
|
||||
|
||||
|
||||
Past Contributors
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
|
||||
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
|
||||
def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions"
|
||||
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
|
||||
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe"
|
||||
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
|
||||
def testResultFilePrefix = "TestResult"
|
||||
def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml"
|
||||
def testResultFilePortable = "${testResultFilePrefix}_UnitTests_portable.xml"
|
||||
def coverageReport = "code_coverage_report.xml"
|
||||
|
||||
|
||||
stage ('Clean output dir') {
|
||||
@@ -32,24 +36,24 @@ node('windows') {
|
||||
withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) {
|
||||
stage ('Build mRemoteNG (Normal - MSI)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Portable)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Normal - MSI)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release\\mRemoteNGTests.dll\""
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release Portable\\mRemoteNGTests.dll\""
|
||||
}
|
||||
stage ('Run Unit Tests (Normal - MSI)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release\\mRemoteNGTests.dll\" --result=${testResultFileNormal} --x86"
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release portable\\mRemoteNGTests.dll\" --result=${testResultFilePortable} --x86"
|
||||
}
|
||||
|
||||
stage ('Generate UpdateCheck Files') {
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\""
|
||||
@@ -58,11 +62,10 @@ node('windows') {
|
||||
|
||||
stage ('Publish to GitHub') {
|
||||
withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) {
|
||||
def zipPath = "${jobDir}\\Release\\*.zip"
|
||||
def msiPath = "${jobDir}\\Release\\*.msi"
|
||||
def releaseFolder = "${jobDir}\\Release"
|
||||
// because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell
|
||||
def base64Description = env.ReleaseDescription.bytes.encodeBase64().toString()
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ZipFilePath \"${zipPath}\" -MsiFilePath \"${msiPath}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ReleaseFolderPath \"${releaseFolder}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
License for use and distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (C) 1999-2016 Igor Pavlov.
|
||||
Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
7-Zip Extra files are under the GNU LGPL license.
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
7-Zip Extra history
|
||||
-------------------
|
||||
|
||||
This file contains only information about changes related to that package exclusively.
|
||||
The full history of changes is listed in history.txt in main 7-Zip program.
|
||||
|
||||
|
||||
18.05 2018-04-30
|
||||
-------------------------
|
||||
- The speed for LZMA/LZMA2 compressing was increased
|
||||
by 8% for fastest/fast compression levels and
|
||||
by 3% for normal/maximum compression levels.
|
||||
|
||||
|
||||
18.03 beta 2018-03-04
|
||||
-------------------------
|
||||
- The speed for single-thread LZMA/LZMA2 decoding
|
||||
was increased by 30% in x64 version and by 3% in x86 version.
|
||||
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
|
||||
if there are multiple independent data chunks in LZMA2 stream.
|
||||
|
||||
|
||||
9.35 beta 2014-12-07
|
||||
------------------------------
|
||||
- SFX modules were moved to LZMA SDK package.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
7-Zip Extra 16.02
|
||||
7-Zip Extra 18.05
|
||||
-----------------
|
||||
|
||||
7-Zip Extra is package of extra modules of 7-Zip.
|
||||
|
||||
7-Zip Copyright (C) 1999-2016 Igor Pavlov.
|
||||
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
7-Zip is free software. Read License.txt for more information about license.
|
||||
|
||||
|
||||
@@ -171,13 +171,27 @@ function Upload-GitHubReleaseAsset {
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
$AuthToken,
|
||||
|
||||
[string]
|
||||
# A short description label for the asset
|
||||
$Label = ""
|
||||
)
|
||||
|
||||
$UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$"
|
||||
$file = Get-Item -Path $FilePath
|
||||
$files = Get-Item -Path $FilePath
|
||||
|
||||
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
|
||||
$labelParam = ""
|
||||
if ($Label -ne "") {
|
||||
$labelParam = "&label=$Label"
|
||||
}
|
||||
|
||||
# Get-Item could produce an array of files if a wildcard is provided. (C:\*.txt)
|
||||
# Upload each matching item individually
|
||||
foreach ($file in $files) {
|
||||
Write-Output "Uploading asset to GitHub release: '$($file.FullName)'"
|
||||
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)$labelParam" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -46,4 +46,5 @@ Format-Table -AutoSize -Wrap -InputObject @{
|
||||
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath
|
||||
& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
@@ -43,13 +43,8 @@ param (
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Path to the zip file to upload with the release
|
||||
$ZipFilePath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#Path to the msi file to upload with the release
|
||||
$MsiFilePath,
|
||||
# Path to the folder which contains release assets to upload
|
||||
$ReleaseFolderPath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
@@ -70,7 +65,17 @@ if ($DescriptionIsBase64Encoded) {
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
|
||||
$releaseFolderItems = Get-ChildItem -Path $ReleaseFolderPath
|
||||
$mrngPortablePath = ($releaseFolderItems | ?{$_.Name -match "portable-[\d\.]+\.zip"}).FullName
|
||||
$mrngNormalPath = ($releaseFolderItems | ?{$_.Name -match "installer-[\d\.]+\.msi"}).FullName
|
||||
$mrngPortableSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-portable-symbols-[\d\.]+\.zip"}).FullName
|
||||
$mrngNormalSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-symbols-[\d\.]+\.zip"}).FullName
|
||||
|
||||
|
||||
$release = Publish-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseTitle $ReleaseTitle -TagName $TagName -TargetCommitish $TargetCommitish -Description $Description -IsDraft ([bool]::Parse($IsDraft)) -IsPrerelease ([bool]::Parse($IsPrerelease)) -AuthToken $AuthToken
|
||||
$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $ZipFilePath -ContentType "application/zip" -AuthToken $AuthToken
|
||||
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken
|
||||
$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngPortablePath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition (zip)"
|
||||
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalPath -ContentType "application/octet-stream" -AuthToken $AuthToken -Label "Normal Edition (msi)"
|
||||
|
||||
$portableEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngPortableSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition Debug Symbols"
|
||||
$normalEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Normal Edition Debug Symbols"
|
||||
Write-Output (Get-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $release.id -AuthToken $AuthToken)
|
||||
@@ -15,7 +15,6 @@ if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Removing unnecessary files from Release versions"
|
||||
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
|
||||
$filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @(
|
||||
"*.pdb",
|
||||
"*.publish",
|
||||
"*.xml",
|
||||
"*.backup",
|
||||
|
||||
@@ -13,13 +13,49 @@ param (
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
$path_packageZipScript = Join-Path -Path $SolutionDir -ChildPath "Tools\build-relport.cmd"
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release" -and $ConfigurationName -match "Portable") {
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
& $path_packageZipScript
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
$tempFolderPath = Join-Path -Path $SolutionDir -ChildPath "mRemoteV1\bin\package"
|
||||
Remove-Item -Recurse $tempFolderPath -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item $tempFolderPath -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination $tempFolderPath
|
||||
|
||||
#Write-Output "$($SolutionDir)mRemoteV1\bin\$ConfigurationName"
|
||||
#Write-Output "$($SolutionDir)mRemoteV1\bin\package"
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination $tempFolderPath -Recurse -Force
|
||||
# Delete any PDB files that accidentally get copied into the temp folder
|
||||
Get-ChildItem -Path $tempFolderPath -Filter "*.pdb" | Remove-Item
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination $tempFolderPath
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip (Join-Path -Path $tempFolderPath -ChildPath "*.*")
|
||||
#& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT"
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
|
||||
39
Tools/zip_portable_files_appv.ps1
Normal file
39
Tools/zip_portable_files_appv.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "NOT running via Appveyor - Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
$appvDir = $Env:APPVEYOR_BUILD_FOLDER
|
||||
|
||||
Write-Output "Appveyor Build Dir: '$($appvDir)'"
|
||||
$ConfigurationName = $Env:CONFIGURATION.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
Remove-Item -Recurse "$($SolutionDir)mRemoteV1\bin\package" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item "$($SolutionDir)mRemoteV1\bin\package" -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination "$($SolutionDir)mRemoteV1\bin\package"
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination "$($SolutionDir)mRemoteV1\bin\package" -Recurse -Force
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination "$($SolutionDir)mRemoteV1\bin\package"
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip "$($SolutionDir)mRemoteV1\bin\package\*.*"
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
}
|
||||
56
Tools/zip_symbols.ps1
Normal file
56
Tools/zip_symbols.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Packaging debug symbols"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
if ($ConfigurationName -match "Portable") {
|
||||
$zipFilePrefix = "mRemoteNG-Portable-symbols"
|
||||
} else {
|
||||
$zipFilePrefix = "mRemoteNG-symbols"
|
||||
}
|
||||
|
||||
$outputZipPath="$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
|
||||
|
||||
Write-Output "Creating debug symbols ZIP file $($outputZipPath)"
|
||||
Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath (Join-Path -Path $TargetDir -ChildPath "*.pdb")
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not package debug symbols - this isnt a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
12
appveyor.yml
12
appveyor.yml
@@ -1,10 +1,11 @@
|
||||
version: 1.0.{build}
|
||||
version: 1.76.{build}
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
image: Visual Studio 2017
|
||||
configuration:
|
||||
- Release
|
||||
- Release Portable
|
||||
- Release Installer
|
||||
platform: x86
|
||||
clone_depth: 1
|
||||
install:
|
||||
@@ -14,7 +15,14 @@ before_build:
|
||||
build:
|
||||
project: mRemoteV1.sln
|
||||
verbosity: normal
|
||||
after_build:
|
||||
- ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"$($SolutionDir)Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"$($SolutionDir)Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"$($SolutionDir)mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"$($SolutionDir)Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"$($SolutionDir)mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"$($SolutionDir)mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"$($SolutionDir)mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Copy-Item \"$($SolutionDir)mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"$($SolutionDir)*.txt\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \"$($SolutionDir)mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}"
|
||||
test:
|
||||
assemblies:
|
||||
only:
|
||||
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
|
||||
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
|
||||
artifacts:
|
||||
- path: Release\*.msi
|
||||
name: mRemoteNG-installer.msi
|
||||
- path: Release\*.zip
|
||||
name: mRemoteNG-portable.zip
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
@@ -19,7 +18,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
|
||||
|
||||
public void Setup(string confCons, string password)
|
||||
{
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(password.ConvertToSecureString);
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString());
|
||||
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using NUnit.Framework;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
@@ -74,6 +75,22 @@ namespace mRemoteNGTests.Connection
|
||||
Assert.That(hasEverythingInheritedProperty, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AlwaysReturnInheritedValueIfRequested()
|
||||
{
|
||||
var expectedSetting = false;
|
||||
|
||||
var container = new ContainerInfo { AutomaticResize = expectedSetting };
|
||||
var con1 = new ConnectionInfo
|
||||
{
|
||||
AutomaticResize = true,
|
||||
Inheritance = {AutomaticResize = true}
|
||||
};
|
||||
container.AddChild(con1);
|
||||
|
||||
Assert.That(con1.AutomaticResize, Is.EqualTo(expectedSetting));
|
||||
}
|
||||
|
||||
private bool AllInheritancePropertiesAreTrue()
|
||||
{
|
||||
var allPropertiesTrue = true;
|
||||
|
||||
@@ -43,6 +43,20 @@ namespace mRemoteNGTests.Connection
|
||||
Assert.That(clonedConnection.Parent, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CloneAlsoCopiesInheritanceObject()
|
||||
{
|
||||
var clonedConnection = _connectionInfo.Clone();
|
||||
Assert.That(clonedConnection.Inheritance, Is.Not.EqualTo(_connectionInfo.Inheritance));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CloneCorrectlySetsParentOfInheritanceObject()
|
||||
{
|
||||
var clonedConnection = _connectionInfo.Clone();
|
||||
Assert.That(clonedConnection.Inheritance.Parent, Is.EqualTo(clonedConnection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyFromCopiesProperties()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
@@ -29,20 +31,19 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
_originalModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_serializer = null;
|
||||
_deserializer = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeThenDeserialize()
|
||||
{
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
@@ -54,7 +55,6 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
{
|
||||
_serializer.UseFullEncryption = true;
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
@@ -66,7 +66,6 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
{
|
||||
var originalConnectionInfo = new ConnectionInfo {Name = "con1", Description = "£°úg¶┬ä" };
|
||||
var serializedContent = _serializer.Serialize(originalConnectionInfo);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
|
||||
Assert.That(deserializedConnectionInfo.Description, Is.EqualTo(originalConnectionInfo.Description));
|
||||
@@ -84,13 +83,26 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GuidCreatedIfNonExistedInXml()
|
||||
{
|
||||
var originalConnectionInfo = new ConnectionInfo { Name = "con1" };
|
||||
var serializedContent = _serializer.Serialize(originalConnectionInfo);
|
||||
|
||||
// remove GUID from connection xml
|
||||
serializedContent = serializedContent.Replace(originalConnectionInfo.ConstantID, "");
|
||||
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
|
||||
Assert.That(Guid.TryParse(deserializedConnectionInfo.ConstantID, out var guid));
|
||||
}
|
||||
|
||||
|
||||
private ConnectionTreeModel SetupConnectionTreeModel()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
@@ -9,35 +10,31 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
{
|
||||
public class PasswordAuthenticatorTests
|
||||
{
|
||||
private PasswordAuthenticator _authenticator;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
private string _cipherText;
|
||||
private readonly SecureString _correctPassword = "9theCorrectPass#5".ConvertToSecureString();
|
||||
private readonly SecureString _wrongPassword = "wrongPassword".ConvertToSecureString();
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var cryptoProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
|
||||
const string cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
|
||||
_authenticator = new PasswordAuthenticator(cryptoProvider, cipherText);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_authenticator = null;
|
||||
_cryptographyProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
|
||||
_cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatingWithCorrectPasswordReturnsTrue()
|
||||
{
|
||||
var authenticated = _authenticator.Authenticate(_correctPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
|
||||
var authenticated = authenticator.Authenticate(_correctPassword);
|
||||
Assert.That(authenticated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatingWithWrongPasswordReturnsFalse()
|
||||
{
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(!authenticated);
|
||||
}
|
||||
|
||||
@@ -45,12 +42,15 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticationRequestorIsCalledWhenInitialPasswordIsWrong()
|
||||
{
|
||||
var wasCalled = false;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
wasCalled = true;
|
||||
return _correctPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(wasCalled);
|
||||
}
|
||||
|
||||
@@ -58,28 +58,30 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticationRequestorNotCalledWhenInitialPasswordIsCorrect()
|
||||
{
|
||||
var wasCalled = false;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
wasCalled = true;
|
||||
return _correctPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_correctPassword);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_correctPassword);
|
||||
Assert.That(!wasCalled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvidingCorrectPasswordToTheAuthenticationRequestorReturnsTrue()
|
||||
{
|
||||
_authenticator.AuthenticationRequestor = () => _correctPassword;
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => _correctPassword);
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authenticated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticationFailsWhenAuthenticationRequestorGivenEmptyPassword()
|
||||
{
|
||||
_authenticator.AuthenticationRequestor = () => new SecureString();
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => new SecureString());
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(!authenticated);
|
||||
}
|
||||
|
||||
@@ -87,27 +89,34 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticatorRespectsMaxAttempts()
|
||||
{
|
||||
var authAttempts = 0;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
authAttempts++;
|
||||
return _wrongPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == _authenticator.MaxAttempts);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == authenticator.MaxAttempts);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatorRespectsMaxAttemptsCustomValue()
|
||||
{
|
||||
const int customMaxAttempts = 5;
|
||||
_authenticator.MaxAttempts = customMaxAttempts;
|
||||
var authAttempts = 0;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
authAttempts++;
|
||||
return _wrongPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
}
|
||||
|
||||
var authenticator =
|
||||
new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor)
|
||||
{
|
||||
MaxAttempts = customMaxAttempts
|
||||
};
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == customMaxAttempts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using mRemoteNG.Connection.Protocol.VNC;
|
||||
|
||||
namespace mRemoteNGTests.TestHelpers
|
||||
{
|
||||
internal class ConnectionInfoHelpers
|
||||
internal static class ConnectionInfoHelpers
|
||||
{
|
||||
private static readonly Random _random = new Random();
|
||||
|
||||
@@ -128,5 +128,5 @@ namespace mRemoteNGTests.TestHelpers
|
||||
var values = Enum.GetValues(typeof(T));
|
||||
return (T)values.GetValue(_random.Next(values.Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
@@ -46,5 +47,13 @@ namespace mRemoteNGTests.Tree
|
||||
_rootNodeInfo.PasswordString = password;
|
||||
Assert.That(_rootNodeInfo.PasswordString, Is.EqualTo(password));
|
||||
}
|
||||
|
||||
[TestCase(RootNodeType.Connection, TreeNodeType.Root)]
|
||||
[TestCase(RootNodeType.PuttySessions, TreeNodeType.PuttyRoot)]
|
||||
public void RootNodeHasCorrectTreeNodeType(RootNodeType rootNodeType, TreeNodeType expectedTreeNodeType)
|
||||
{
|
||||
var rootNode = new RootNodeInfo(rootNodeType);
|
||||
Assert.That(rootNode.GetTreeNodeType(), Is.EqualTo(expectedTreeNodeType));
|
||||
}
|
||||
}
|
||||
}
|
||||
202
mRemoteNGTests/UI/Controls/ConnectionTreeTests.cs
Normal file
202
mRemoteNGTests/UI/Controls/ConnectionTreeTests.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Controls;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Controls
|
||||
{
|
||||
public class ConnectionTreeTests
|
||||
{
|
||||
private ConnectionTreeSearchTextFilter _filter;
|
||||
private ConnectionTree _connectionTree;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_filter = new ConnectionTreeSearchTextFilter();
|
||||
_connectionTree = new ConnectionTree
|
||||
{
|
||||
UseFiltering = true
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void FilteringIsRetainedAndUpdatedWhenNodeDeleted()
|
||||
{
|
||||
// root
|
||||
// |- folder1
|
||||
// | |- con1
|
||||
// | |- dontshowme
|
||||
// |- folder2
|
||||
// |- con2
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var folder1 = new ContainerInfo {Name = "folder1"};
|
||||
var folder2 = new ContainerInfo {Name = "folder2"};
|
||||
var con1 = new ConnectionInfo {Name = "con1"};
|
||||
var con2 = new ConnectionInfo {Name = "con2"};
|
||||
var conDontShow = new ConnectionInfo {Name = "dontshowme" };
|
||||
root.AddChildRange(new []{folder1, folder2});
|
||||
folder1.AddChildRange(new []{con1, conDontShow});
|
||||
folder2.AddChild(con2);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
// ensure all folders expanded
|
||||
_connectionTree.ExpandAll();
|
||||
|
||||
// apply filtering on the tree
|
||||
_filter.FilterText = "con";
|
||||
_connectionTree.ModelFilter = _filter;
|
||||
|
||||
connectionTreeModel.DeleteNode(con1);
|
||||
|
||||
Assert.That(_connectionTree.IsFiltering, Is.True);
|
||||
Assert.That(_connectionTree.FilteredObjects, Does.Not.Contain(con1));
|
||||
Assert.That(_connectionTree.FilteredObjects, Does.Not.Contain(conDontShow));
|
||||
Assert.That(_connectionTree.FilteredObjects, Does.Contain(con2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotAddConnectionToPuttySessionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = puttyRoot;
|
||||
_connectionTree.AddConnection();
|
||||
|
||||
Assert.That(puttyRoot.Children, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotAddFolderToPuttySessionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = puttyRoot;
|
||||
_connectionTree.AddFolder();
|
||||
|
||||
Assert.That(puttyRoot.Children, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotDuplicateRootConnectionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = root;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotDuplicateRootPuttyNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = puttyRoot;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotDuplicatePuttyConnectionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
var puttyConnection = new PuttySessionInfo();
|
||||
puttyRoot.AddChild(puttyConnection);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
_connectionTree.ExpandAll();
|
||||
|
||||
_connectionTree.SelectedObject = puttyConnection;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(puttyRoot.Children, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void DuplicatingWithNoNodeSelectedDoesNothing()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = null;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void ExpandingAllItemsUpdatesColumnWidthAppropriately()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
ContainerInfo parent = root;
|
||||
foreach (var i in Enumerable.Repeat("", 8))
|
||||
{
|
||||
var newContainer = new ContainerInfo {IsExpanded = false};
|
||||
parent.AddChild(newContainer);
|
||||
parent = newContainer;
|
||||
}
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
var widthBefore = _connectionTree.Columns[0].Width;
|
||||
_connectionTree.ExpandAll();
|
||||
var widthAfter = _connectionTree.Columns[0].Width;
|
||||
|
||||
Assert.That(widthAfter, Is.GreaterThan(widthBefore));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void RenamingNodeWithNothingSelectedDoesNothing()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
_connectionTree.SelectedObject = null;
|
||||
|
||||
Assert.DoesNotThrow(() => _connectionTree.RenameSelectedNode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Window;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public class ConfigWindowGeneralTests
|
||||
{
|
||||
private ConfigWindow _configWindow;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_configWindow = new ConfigWindow
|
||||
{
|
||||
PropertiesVisible = true
|
||||
};
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(ConnectionInfoGeneralTestCases))]
|
||||
public void PropertyGridShowCorrectPropertiesForConnectionInfo(ConnectionInfo connectionInfo, IEnumerable<string> expectedVisibleProperties)
|
||||
{
|
||||
_configWindow.SelectedTreeNode = connectionInfo;
|
||||
Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PropertyGridShowCorrectPropertiesForRootConnectionInfo()
|
||||
{
|
||||
var expectedVisibleProperties = new[]
|
||||
{
|
||||
nameof(RootNodeInfo.Name),
|
||||
nameof(RootNodeInfo.Password),
|
||||
};
|
||||
|
||||
_configWindow.SelectedTreeNode = new RootNodeInfo(RootNodeType.Connection);
|
||||
Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PropertyGridShowCorrectPropertiesForRootPuttyInfo()
|
||||
{
|
||||
var expectedVisibleProperties = new[]
|
||||
{
|
||||
nameof(RootNodeInfo.Name),
|
||||
};
|
||||
|
||||
_configWindow.SelectedTreeNode = new RootPuttySessionsNodeInfo();
|
||||
Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties));
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> ConnectionInfoGeneralTestCases()
|
||||
{
|
||||
var protocolTypes = typeof(ProtocolType).GetEnumValues().OfType<ProtocolType>();
|
||||
var testCases = new List<TestCaseData>();
|
||||
|
||||
foreach (var protocol in protocolTypes)
|
||||
{
|
||||
var expectedPropertyListConnection = BuildExpectedConnectionInfoPropertyList(protocol, false);
|
||||
var connectionInfo = ConstructConnectionInfo(protocol, false);
|
||||
var testCaseConnection = new TestCaseData(connectionInfo, expectedPropertyListConnection)
|
||||
.SetName(protocol + ", ConnectionInfo");
|
||||
testCases.Add(testCaseConnection);
|
||||
|
||||
var expectedPropertyListContainer = BuildExpectedConnectionInfoPropertyList(protocol, true);
|
||||
var containerInfo = ConstructConnectionInfo(protocol, true);
|
||||
var testCaseContainer = new TestCaseData(containerInfo, expectedPropertyListContainer)
|
||||
.SetName(protocol + ", ContainerInfo");
|
||||
testCases.Add(testCaseContainer);
|
||||
}
|
||||
|
||||
return testCases;
|
||||
}
|
||||
|
||||
internal static ConnectionInfo ConstructConnectionInfo(ProtocolType protocol, bool isContainer)
|
||||
{
|
||||
// build connection info. set certain connection properties so
|
||||
// that toggled properties are hidden in the property grid. We
|
||||
// will test those separately in the special protocol tests.
|
||||
var node = isContainer
|
||||
? new ContainerInfo()
|
||||
: new ConnectionInfo();
|
||||
|
||||
node.Protocol = protocol;
|
||||
node.Resolution = RdpProtocol.RDPResolutions.Res800x600;
|
||||
node.RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Never;
|
||||
node.RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.Yes;
|
||||
node.RedirectSound = RdpProtocol.RDPSounds.DoNotPlay;
|
||||
node.VNCAuthMode = ProtocolVNC.AuthMode.AuthVNC;
|
||||
node.VNCProxyType = ProtocolVNC.ProxyType.ProxyNone;
|
||||
node.Inheritance.TurnOffInheritanceCompletely();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
internal static List<string> BuildExpectedConnectionInfoPropertyList(ProtocolType protocol, bool isContainer)
|
||||
{
|
||||
var expectedProperties = new List<string>
|
||||
{
|
||||
nameof(ConnectionInfo.Name),
|
||||
nameof(ConnectionInfo.Description),
|
||||
nameof(ConnectionInfo.Icon),
|
||||
nameof(ConnectionInfo.Panel),
|
||||
nameof(ConnectionInfo.Protocol),
|
||||
nameof(ConnectionInfo.PreExtApp),
|
||||
nameof(ConnectionInfo.PostExtApp),
|
||||
nameof(ConnectionInfo.MacAddress),
|
||||
nameof(ConnectionInfo.UserField),
|
||||
};
|
||||
|
||||
if (!isContainer)
|
||||
{
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Hostname),
|
||||
});
|
||||
}
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case ProtocolType.RDP:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.UseConsoleSession),
|
||||
nameof(ConnectionInfo.RDPAuthenticationLevel),
|
||||
nameof(ConnectionInfo.RDPMinutesToIdleTimeout),
|
||||
nameof(ConnectionInfo.LoadBalanceInfo),
|
||||
nameof(ConnectionInfo.UseCredSsp),
|
||||
nameof(ConnectionInfo.RDGatewayUsageMethod),
|
||||
nameof(ConnectionInfo.Resolution),
|
||||
nameof(ConnectionInfo.Colors),
|
||||
nameof(ConnectionInfo.CacheBitmaps),
|
||||
nameof(ConnectionInfo.DisplayWallpaper),
|
||||
nameof(ConnectionInfo.DisplayThemes),
|
||||
nameof(ConnectionInfo.EnableFontSmoothing),
|
||||
nameof(ConnectionInfo.EnableDesktopComposition),
|
||||
nameof(ConnectionInfo.RedirectKeys),
|
||||
nameof(ConnectionInfo.RedirectDiskDrives),
|
||||
nameof(ConnectionInfo.RedirectPrinters),
|
||||
nameof(ConnectionInfo.RedirectPorts),
|
||||
nameof(ConnectionInfo.RedirectSmartCards),
|
||||
nameof(ConnectionInfo.RedirectSound),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.VNC:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.VNCSmartSizeMode),
|
||||
nameof(ConnectionInfo.VNCViewOnly),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.SSH1:
|
||||
case ProtocolType.SSH2:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.PuttySession)
|
||||
});
|
||||
break;
|
||||
case ProtocolType.Telnet:
|
||||
case ProtocolType.Rlogin:
|
||||
case ProtocolType.RAW:
|
||||
expectedProperties.AddRange(new[]
|
||||
{
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.PuttySession),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.HTTP:
|
||||
case ProtocolType.HTTPS:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.RenderingEngine),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.ICA:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
nameof(ConnectionInfo.ICAEncryptionStrength),
|
||||
nameof(ConnectionInfo.Resolution),
|
||||
nameof(ConnectionInfo.Colors),
|
||||
nameof(ConnectionInfo.CacheBitmaps),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.IntApp:
|
||||
expectedProperties.AddRange(new[]
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.ExtApp),
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(protocol), protocol, null);
|
||||
}
|
||||
|
||||
return expectedProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public class ConfigWindowRdpSpecialTests : ConfigWindowSpecialTestsBase
|
||||
{
|
||||
protected override ProtocolType Protocol => ProtocolType.RDP;
|
||||
|
||||
[Test]
|
||||
public void PropertyShownWhenActive_RdpMinutesToIdleTimeout()
|
||||
{
|
||||
ConnectionInfo.RDPMinutesToIdleTimeout = 1;
|
||||
ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.RDPAlertIdleTimeout));
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[TestCase(RdpProtocol.RDGatewayUsageMethod.Always)]
|
||||
[TestCase(RdpProtocol.RDGatewayUsageMethod.Detect)]
|
||||
public void RdGatewayPropertiesShown_WhenRdGatewayUsageMethodIsNotNever(RdpProtocol.RDGatewayUsageMethod gatewayUsageMethod)
|
||||
{
|
||||
ConnectionInfo.RDGatewayUsageMethod = gatewayUsageMethod;
|
||||
ConnectionInfo.RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.Yes;
|
||||
ExpectedPropertyList.AddRange(new []
|
||||
{
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayHostname),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUseConnectionCredentials)
|
||||
});
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[TestCase(RdpProtocol.RDGatewayUseConnectionCredentials.No)]
|
||||
[TestCase(RdpProtocol.RDGatewayUseConnectionCredentials.SmartCard)]
|
||||
public void RdGatewayPropertiesShown_WhenRDGatewayUseConnectionCredentialsIsNotYes(RdpProtocol.RDGatewayUseConnectionCredentials useConnectionCredentials)
|
||||
{
|
||||
ConnectionInfo.RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Always;
|
||||
ConnectionInfo.RDGatewayUseConnectionCredentials = useConnectionCredentials;
|
||||
ExpectedPropertyList.AddRange(new []
|
||||
{
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayHostname),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUsername),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayPassword),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayDomain),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUseConnectionCredentials)
|
||||
});
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SoundQualityPropertyShown_WhenRdpSoundsSetToBringToThisComputer()
|
||||
{
|
||||
ConnectionInfo.RedirectSound = RdpProtocol.RDPSounds.BringToThisComputer;
|
||||
ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.SoundQuality));
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[TestCase(RdpProtocol.RDPResolutions.FitToWindow)]
|
||||
[TestCase(RdpProtocol.RDPResolutions.Fullscreen)]
|
||||
public void AutomaticResizePropertyShown_WhenResolutionIsDynamic(RdpProtocol.RDPResolutions resolution)
|
||||
{
|
||||
ConnectionInfo.Resolution = resolution;
|
||||
ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.AutomaticResize));
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.UI.Window;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public abstract class ConfigWindowSpecialTestsBase
|
||||
{
|
||||
protected abstract ProtocolType Protocol { get; }
|
||||
protected bool TestAgainstContainerInfo { get; set; } = false;
|
||||
protected ConfigWindow ConfigWindow;
|
||||
protected ConnectionInfo ConnectionInfo;
|
||||
protected List<string> ExpectedPropertyList;
|
||||
|
||||
[SetUp]
|
||||
public virtual void Setup()
|
||||
{
|
||||
ConnectionInfo = ConfigWindowGeneralTests.ConstructConnectionInfo(Protocol, TestAgainstContainerInfo);
|
||||
ExpectedPropertyList = ConfigWindowGeneralTests.BuildExpectedConnectionInfoPropertyList(Protocol, TestAgainstContainerInfo);
|
||||
|
||||
ConfigWindow = new ConfigWindow
|
||||
{
|
||||
PropertiesVisible = true,
|
||||
};
|
||||
}
|
||||
|
||||
public void RunVerification()
|
||||
{
|
||||
ConfigWindow.SelectedTreeNode = ConnectionInfo;
|
||||
Assert.That(
|
||||
ConfigWindow.VisibleObjectProperties,
|
||||
Is.EquivalentTo(ExpectedPropertyList));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public class ConfigWindowVncSpecialTests : ConfigWindowSpecialTestsBase
|
||||
{
|
||||
protected override ProtocolType Protocol => ProtocolType.VNC;
|
||||
|
||||
[Test]
|
||||
public void UserDomainPropertiesShown_WhenAuthModeIsWindows()
|
||||
{
|
||||
ConnectionInfo.VNCAuthMode = ProtocolVNC.AuthMode.AuthWin;
|
||||
ExpectedPropertyList.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(ProtocolVNC.ProxyType.ProxyHTTP)]
|
||||
[TestCase(ProtocolVNC.ProxyType.ProxySocks5)]
|
||||
[TestCase(ProtocolVNC.ProxyType.ProxyUltra)]
|
||||
public void ProxyPropertiesShown_WhenProxyModeIsNotNone(ProtocolVNC.ProxyType proxyType)
|
||||
{
|
||||
ConnectionInfo.VNCProxyType = proxyType;
|
||||
ExpectedPropertyList.AddRange(new[]
|
||||
{
|
||||
nameof(ConnectionInfo.VNCProxyIP),
|
||||
nameof(ConnectionInfo.VNCProxyPort),
|
||||
nameof(ConnectionInfo.VNCProxyUsername),
|
||||
nameof(ConnectionInfo.VNCProxyPassword),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,6 +207,7 @@
|
||||
<Compile Include="Tree\RootNodeInfoTests.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandlerTests.cs" />
|
||||
<Compile Include="Tree\SelectedConnectionDeletionConfirmerTests.cs" />
|
||||
<Compile Include="UI\Controls\ConnectionTreeTests.cs" />
|
||||
<Compile Include="UI\Controls\PageSequenceTests.cs" />
|
||||
<Compile Include="UI\Controls\SecureTextBoxTestForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -231,6 +232,10 @@
|
||||
<Compile Include="UI\Forms\OptionsFormSetupAndTeardown.cs" />
|
||||
<Compile Include="UI\Forms\PasswordFormTests.cs" />
|
||||
<Compile Include="UI\WindowListTests.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowGeneralTests.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowRdpSpecialTests.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowSpecialTestsBase.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowVncSpecialTests.cs" />
|
||||
<Compile Include="UI\Window\ConnectionTreeWindowTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -33,16 +33,19 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.Build.0 = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.Build.0 = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
@@ -50,24 +53,26 @@ Global
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.Build.0 = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.Build.0 = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x86.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.ActiveCfg = Debug|x86
|
||||
@@ -77,7 +82,6 @@ Global
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|Any CPU.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|x86.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.Build.0 = Release|x86
|
||||
@@ -86,8 +90,8 @@ Global
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.Build.0 = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
|
||||
@@ -4,8 +4,6 @@ using System.Security;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
@@ -20,7 +18,7 @@ using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
public static class Runtime
|
||||
public static class Runtime
|
||||
{
|
||||
public static bool IsPortableEdition
|
||||
{
|
||||
@@ -79,12 +77,6 @@ namespace mRemoteNG.App
|
||||
{
|
||||
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
|
||||
}
|
||||
|
||||
var backupFileCreator = new FileBackupCreator();
|
||||
backupFileCreator.CreateBackupFile(connectionFileName);
|
||||
|
||||
var backupPruner = new FileBackupPruner();
|
||||
backupPruner.PruneBackupFiles(connectionFileName);
|
||||
}
|
||||
|
||||
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
|
||||
@@ -93,18 +85,6 @@ namespace mRemoteNG.App
|
||||
{
|
||||
ConnectionsService.LastSqlUpdate = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (connectionFileName == ConnectionsService.GetDefaultStartupConnectionFileName())
|
||||
{
|
||||
Settings.Default.LoadConsFromCustomLocation = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Settings.Default.LoadConsFromCustomLocation = true;
|
||||
Settings.Default.CustomConsPath = connectionFileName;
|
||||
}
|
||||
}
|
||||
|
||||
// re-enable sql update checking after updates are loaded
|
||||
ConnectionsService.RemoteConnectionsSyncronizer?.Enable();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Window;
|
||||
using System;
|
||||
using System;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.UI;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Window;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
@@ -15,8 +15,14 @@ namespace mRemoteNG.App
|
||||
private static PortScanWindow _portscanForm;
|
||||
private static UltraVNCWindow _ultravncscForm;
|
||||
private static ComponentsCheckWindow _componentscheckForm;
|
||||
private static ConnectionTreeWindow _treeForm;
|
||||
|
||||
internal static ConnectionTreeWindow TreeForm
|
||||
{
|
||||
get => _treeForm ?? (_treeForm = new ConnectionTreeWindow());
|
||||
set => _treeForm = value;
|
||||
}
|
||||
|
||||
internal static ConnectionTreeWindow TreeForm { get; set; } = new ConnectionTreeWindow();
|
||||
internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow();
|
||||
internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow();
|
||||
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
@@ -20,10 +21,9 @@ namespace mRemoteNG.Config.Connections
|
||||
|
||||
private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
|
||||
{
|
||||
|
||||
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
|
||||
|
||||
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
|
||||
{
|
||||
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
|
||||
@@ -45,7 +45,10 @@ namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
if (!mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit)
|
||||
return;
|
||||
_connectionsService.SaveConnections();
|
||||
if (FrmMain.Default.IsClosing)
|
||||
return;
|
||||
|
||||
_connectionsService.SaveConnectionsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using System.IO;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class XmlConnectionsLoader
|
||||
public class XmlConnectionsLoader
|
||||
{
|
||||
private readonly string _connectionFilePath;
|
||||
|
||||
@@ -32,7 +31,7 @@ namespace mRemoteNG.Config.Connections
|
||||
return deserializer.Deserialize(xmlString);
|
||||
}
|
||||
|
||||
private SecureString PromptForPassword()
|
||||
private Optional<SecureString> PromptForPassword()
|
||||
{
|
||||
var password = MiscTools.PasswordDialog("", false);
|
||||
return password;
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
public class FileBackupPruner
|
||||
{
|
||||
public void PruneBackupFiles(string baseName)
|
||||
public void PruneBackupFiles(string filePath, int maxBackupsToKeep)
|
||||
{
|
||||
var fileName = Path.GetFileName(baseName);
|
||||
var directoryName = Path.GetDirectoryName(baseName);
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
var directoryName = Path.GetDirectoryName(filePath);
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(directoryName)) return;
|
||||
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(directoryName))
|
||||
return;
|
||||
|
||||
var searchPattern = string.Format(mRemoteNG.Settings.Default.BackupFileNameFormat, fileName, "*");
|
||||
var files = Directory.GetFiles(directoryName, searchPattern);
|
||||
|
||||
if (files.Length <= mRemoteNG.Settings.Default.BackupFileKeepCount) return;
|
||||
if (files.Length <= maxBackupsToKeep)
|
||||
return;
|
||||
|
||||
Array.Sort(files);
|
||||
Array.Resize(ref files, files.Length - mRemoteNG.Settings.Default.BackupFileKeepCount);
|
||||
var filesToDelete = files
|
||||
.OrderByDescending(s => s)
|
||||
.Skip(maxBackupsToKeep);
|
||||
|
||||
foreach (var file in files)
|
||||
foreach (var file in filesToDelete)
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using mRemoteNG.Tools;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree.Root;
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
public class PuttySessionsManager
|
||||
public class PuttySessionsManager
|
||||
{
|
||||
public static PuttySessionsManager Instance { get; } = new PuttySessionsManager();
|
||||
|
||||
@@ -35,10 +35,12 @@ namespace mRemoteNG.Config.Putty
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSessionsFromProvider(AbstractPuttySessionsProvider provider)
|
||||
private void AddSessionsFromProvider(AbstractPuttySessionsProvider puttySessionProvider)
|
||||
{
|
||||
var rootTreeNode = provider.RootInfo;
|
||||
provider.GetSessions();
|
||||
puttySessionProvider.ThrowIfNull(nameof(puttySessionProvider));
|
||||
|
||||
var rootTreeNode = puttySessionProvider.RootInfo;
|
||||
puttySessionProvider.GetSessions();
|
||||
|
||||
if (!RootPuttySessionsNodes.Contains(rootTreeNode) && rootTreeNode.HasChildren())
|
||||
RootPuttySessionsNodes.Add(rootTreeNode);
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using Microsoft.Win32;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Microsoft.Win32;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Messages;
|
||||
|
||||
|
||||
namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider
|
||||
public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider
|
||||
{
|
||||
private const string PuttySessionsKey = "Software\\SimonTatham\\PuTTY\\Sessions";
|
||||
private static ManagementEventWatcher _eventWatcher;
|
||||
@@ -39,7 +39,10 @@ namespace mRemoteNG.Config.Putty
|
||||
}
|
||||
|
||||
public override PuttySessionInfo GetSession(string sessionName)
|
||||
{
|
||||
{
|
||||
if (string.IsNullOrEmpty(sessionName))
|
||||
return null;
|
||||
|
||||
var sessionsKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey);
|
||||
var sessionKey = sessionsKey?.OpenSubKey(sessionName);
|
||||
if (sessionKey == null) return null;
|
||||
@@ -50,10 +53,15 @@ namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
PuttySession = sessionName,
|
||||
Name = sessionName,
|
||||
Hostname = Convert.ToString(sessionKey.GetValue("HostName")),
|
||||
Username = Convert.ToString(sessionKey.GetValue("UserName"))
|
||||
Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "",
|
||||
Username = sessionKey.GetValue("UserName")?.ToString() ?? ""
|
||||
};
|
||||
var protocol = Convert.ToString(sessionKey.GetValue("Protocol")) ?? "ssh";
|
||||
|
||||
|
||||
var protocol = string.IsNullOrEmpty(sessionKey.GetValue("Protocol")?.ToString())
|
||||
? "ssh"
|
||||
: sessionKey.GetValue("Protocol").ToString();
|
||||
|
||||
switch (protocol.ToLowerInvariant())
|
||||
{
|
||||
case "raw":
|
||||
@@ -65,16 +73,15 @@ namespace mRemoteNG.Config.Putty
|
||||
case "serial":
|
||||
return null;
|
||||
case "ssh":
|
||||
var sshVersionObject = sessionKey.GetValue("SshProt");
|
||||
if (sshVersionObject != null)
|
||||
{
|
||||
var sshVersion = Convert.ToInt32(sshVersionObject);
|
||||
sessionInfo.Protocol = sshVersion >= 2 ? ProtocolType.SSH2 : ProtocolType.SSH1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sessionInfo.Protocol = ProtocolType.SSH2;
|
||||
}
|
||||
int.TryParse(sessionKey.GetValue("SshProt")?.ToString(), out var sshVersion);
|
||||
/* Per PUTTY.H in PuTTYNG & PuTTYNG Upstream (PuTTY proper currently)
|
||||
* expect 0 for SSH1, 3 for SSH2 ONLY
|
||||
* 1 for SSH1 with a 2 fallback
|
||||
* 2 for SSH2 with a 1 fallback
|
||||
*
|
||||
* default to SSH2 if any other value is received
|
||||
*/
|
||||
sessionInfo.Protocol = sshVersion == 1 || sshVersion == 0 ? ProtocolType.SSH1 : ProtocolType.SSH2;
|
||||
break;
|
||||
case "telnet":
|
||||
sessionInfo.Protocol = ProtocolType.Telnet;
|
||||
@@ -82,7 +89,12 @@ namespace mRemoteNG.Config.Putty
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
sessionInfo.Port = Convert.ToInt32(sessionKey.GetValue("PortNumber"));
|
||||
|
||||
int.TryParse(sessionKey.GetValue("PortNumber")?.ToString(), out var portNumber);
|
||||
if (portNumber == default(int))
|
||||
sessionInfo.SetDefaultPort();
|
||||
else
|
||||
sessionInfo.Port = portNumber;
|
||||
|
||||
return sessionInfo;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace mRemoteNG.Config.Putty
|
||||
foreach (var sessionName in Directory.GetFiles(sessionsFolderPath))
|
||||
{
|
||||
var sessionFileName = Path.GetFileName(sessionName);
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
sessionNames.Add(raw ? sessionFileName : System.Web.HttpUtility.UrlDecode(sessionFileName?.Replace("+", "%2B")));
|
||||
}
|
||||
|
||||
@@ -125,9 +126,6 @@ namespace mRemoteNG.Config.Putty
|
||||
|
||||
public override void StartWatcher()
|
||||
{
|
||||
PuttySessionsRegistryProvider.StartWatcher();
|
||||
PuttySessionsRegistryProvider.PuttySessionChanged += OnRegistrySessionChanged;
|
||||
|
||||
if (_eventWatcher != null)
|
||||
{
|
||||
return;
|
||||
@@ -136,18 +134,22 @@ namespace mRemoteNG.Config.Putty
|
||||
try
|
||||
{
|
||||
var sessionsFolderPath = GetSessionsFolderPath();
|
||||
if (Directory.Exists(sessionsFolderPath))
|
||||
{
|
||||
_eventWatcher = new FileSystemWatcher(sessionsFolderPath)
|
||||
{
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
|
||||
};
|
||||
_eventWatcher.Changed += OnFileSystemEventArrived;
|
||||
_eventWatcher.Created += OnFileSystemEventArrived;
|
||||
_eventWatcher.Deleted += OnFileSystemEventArrived;
|
||||
_eventWatcher.Renamed += OnFileSystemEventArrived;
|
||||
_eventWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(sessionsFolderPath))
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"XmingPortablePuttySessions.Watcher.StartWatching() failed: '{sessionsFolderPath}' does not exist.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
_eventWatcher = new FileSystemWatcher(sessionsFolderPath)
|
||||
{
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
|
||||
};
|
||||
_eventWatcher.Changed += OnFileSystemEventArrived;
|
||||
_eventWatcher.Created += OnFileSystemEventArrived;
|
||||
_eventWatcher.Deleted += OnFileSystemEventArrived;
|
||||
_eventWatcher.Renamed += OnFileSystemEventArrived;
|
||||
_eventWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -173,7 +175,8 @@ namespace mRemoteNG.Config.Putty
|
||||
private static string GetPuttyConfPath()
|
||||
{
|
||||
var puttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : App.Info.GeneralAppInfo.PuttyPath;
|
||||
return Path.Combine(Path.GetDirectoryName(puttyPath), "putty.conf");
|
||||
puttyPath = Path.GetDirectoryName(puttyPath);
|
||||
return string.IsNullOrEmpty(puttyPath) ? null : Path.Combine(puttyPath, "putty.conf");
|
||||
}
|
||||
|
||||
private static string GetSessionsFolderPath()
|
||||
@@ -200,6 +203,9 @@ namespace mRemoteNG.Config.Putty
|
||||
|
||||
private static PuttySessionInfo ModifyRegistrySessionInfo(PuttySessionInfo sessionInfo)
|
||||
{
|
||||
if (sessionInfo == null)
|
||||
return null;
|
||||
|
||||
sessionInfo.Name = string.Format(RegistrySessionNameFormat, sessionInfo.Name);
|
||||
sessionInfo.PuttySession = string.Format(RegistrySessionNameFormat, sessionInfo.PuttySession);
|
||||
return sessionInfo;
|
||||
|
||||
@@ -13,6 +13,7 @@ using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Forms;
|
||||
@@ -20,7 +21,7 @@ using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
{
|
||||
private XmlDocument _xmlDocument;
|
||||
private double _confVersion;
|
||||
@@ -29,9 +30,9 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
private const double MaxSupportedConfVersion = 2.8;
|
||||
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
|
||||
|
||||
public XmlConnectionsDeserializer(Func<SecureString> authenticationRequestor = null)
|
||||
public XmlConnectionsDeserializer(Func<Optional<SecureString>> authenticationRequestor = null)
|
||||
{
|
||||
AuthenticationRequestor = authenticationRequestor;
|
||||
}
|
||||
@@ -47,8 +48,6 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
LoadXmlConnectionData(xml);
|
||||
ValidateConnectionFileVersion();
|
||||
if (!import)
|
||||
Runtime.ConnectionsService.IsConnectionsFileLoaded = false;
|
||||
|
||||
var rootXmlElement = _xmlDocument.DocumentElement;
|
||||
InitializeRootNode(rootXmlElement);
|
||||
@@ -62,8 +61,6 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
|
||||
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()))
|
||||
{
|
||||
mRemoteNG.Settings.Default.LoadConsFromCustomLocation = false;
|
||||
mRemoteNG.Settings.Default.CustomConsPath = "";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -208,7 +205,9 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
if (xmlnode.Attributes == null) return null;
|
||||
|
||||
var connectionId = xmlnode.Attributes["Id"]?.Value ?? Guid.NewGuid().ToString();
|
||||
var connectionId = xmlnode.Attributes["Id"]?.Value;
|
||||
if (string.IsNullOrWhiteSpace(connectionId))
|
||||
connectionId = Guid.NewGuid().ToString();
|
||||
var connectionInfo = new ConnectionInfo(connectionId);
|
||||
|
||||
try
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
@@ -7,8 +9,6 @@ using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
@@ -60,7 +60,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
else
|
||||
{
|
||||
var versionNode = rdcManNode.SelectSingleNode("./version")?.InnerText;
|
||||
var versionNode = rdcManNode?.SelectSingleNode("./version")?.InnerText;
|
||||
if (versionNode != null)
|
||||
{
|
||||
var version = new Version(versionNode);
|
||||
@@ -101,15 +101,16 @@ namespace mRemoteNG.Config.Serializers
|
||||
{
|
||||
if (_schemaVersion == 1)
|
||||
{
|
||||
// Program Verison 2.2 wraps all setting inside the Properties tags
|
||||
// Program Version 2.2 wraps all setting inside the Properties tags
|
||||
containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
|
||||
}
|
||||
var newContainer = new ContainerInfo();
|
||||
var connectionInfo = ConnectionInfoFromXml(containerPropertiesNode);
|
||||
newContainer.CopyFrom(connectionInfo);
|
||||
|
||||
if (_schemaVersion == 3)
|
||||
{
|
||||
// Program Verison 2.7 wraps these properties
|
||||
// Program Version 2.7 wraps these properties
|
||||
containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
|
||||
}
|
||||
newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.strNewFolder;
|
||||
@@ -130,20 +131,22 @@ namespace mRemoteNG.Config.Serializers
|
||||
|
||||
|
||||
var propertiesNode = xmlNode.SelectSingleNode("./properties");
|
||||
if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead
|
||||
connectionInfo.Hostname = propertiesNode.SelectSingleNode("./name")?.InnerText;
|
||||
connectionInfo.Name = propertiesNode.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname;
|
||||
connectionInfo.Description = propertiesNode.SelectSingleNode("./comment")?.InnerText ?? String.Empty;
|
||||
if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead
|
||||
connectionInfo.Hostname = propertiesNode?.SelectSingleNode("./name")?.InnerText ?? "";
|
||||
connectionInfo.Name = propertiesNode?.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname;
|
||||
connectionInfo.Description = propertiesNode?.SelectSingleNode("./comment")?.InnerText ?? string.Empty;
|
||||
|
||||
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
|
||||
if (logonCredentialsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (logonCredentialsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText;
|
||||
|
||||
var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
|
||||
if (_schemaVersion == 1) // Version 2.2 allows clear text passwords
|
||||
{
|
||||
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"].Value == "True" ? passwordNode.InnerText : DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,7 +163,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var connectionSettingsNode = xmlNode.SelectSingleNode("./connectionSettings");
|
||||
if (connectionSettingsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (connectionSettingsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
connectionInfo.UseConsoleSession = bool.Parse(connectionSettingsNode.SelectSingleNode("./connectToConsole")?.InnerText ?? "false");
|
||||
// ./startProgram
|
||||
@@ -174,7 +177,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var gatewaySettingsNode = xmlNode.SelectSingleNode("./gatewaySettings");
|
||||
if (gatewaySettingsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (gatewaySettingsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
connectionInfo.RDGatewayUsageMethod = gatewaySettingsNode.SelectSingleNode("./enabled")?.InnerText == "True" ? RdpProtocol.RDGatewayUsageMethod.Always : RdpProtocol.RDGatewayUsageMethod.Never;
|
||||
connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName")?.InnerText;
|
||||
@@ -198,7 +201,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var remoteDesktopNode = xmlNode.SelectSingleNode("./remoteDesktop");
|
||||
if (remoteDesktopNode?.Attributes?["inherit"].Value == "None")
|
||||
if (remoteDesktopNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
var resolutionString = remoteDesktopNode.SelectSingleNode("./size")?.InnerText.Replace(" ", "");
|
||||
try
|
||||
@@ -231,7 +234,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var localResourcesNode = xmlNode.SelectSingleNode("./localResources");
|
||||
if (localResourcesNode?.Attributes?["inherit"].Value == "None")
|
||||
if (localResourcesNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (localResourcesNode.SelectSingleNode("./audioRedirection")?.InnerText)
|
||||
@@ -271,10 +274,10 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
// ./redirectClipboard
|
||||
connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode.SelectSingleNode("./redirectDrives")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectPorts = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPorts")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectDrives")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectPorts = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPorts")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode?.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -287,7 +290,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings");
|
||||
if (securitySettingsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (securitySettingsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (securitySettingsNode.SelectSingleNode("./authentication")?.InnerText)
|
||||
@@ -321,7 +324,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
private static string DecryptRdcManPassword(string ciphertext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ciphertext))
|
||||
return null;
|
||||
return string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -332,7 +335,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
catch (Exception /*ex*/)
|
||||
{
|
||||
//Runtime.MessageCollector.AddExceptionMessage("RemoteDesktopConnectionManager.DecryptPassword() failed.", ex, logOnly: true);
|
||||
return null;
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
@@ -13,7 +14,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly RootNodeInfo _rootNodeInfo;
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
|
||||
|
||||
public int KeyDerivationIterations
|
||||
{
|
||||
@@ -91,16 +92,14 @@ namespace mRemoteNG.Config.Serializers
|
||||
|
||||
private bool Authenticate(string cipherText, SecureString password)
|
||||
{
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText)
|
||||
{
|
||||
AuthenticationRequestor = AuthenticationRequestor
|
||||
};
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText, AuthenticationRequestor);
|
||||
var authenticated = authenticator.Authenticate(password);
|
||||
|
||||
if (!authenticated) return authenticated;
|
||||
if (!authenticated)
|
||||
return false;
|
||||
|
||||
_rootNodeInfo.PasswordString = authenticator.LastAuthenticatedPassword.ConvertToUnsecureString();
|
||||
return authenticated;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Configuration;
|
||||
#if !PORTABLE
|
||||
using System.Configuration;
|
||||
#endif
|
||||
|
||||
namespace mRemoteNG.Config.Settings.Providers
|
||||
{
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
/// The MIT License (MIT)
|
||||
///
|
||||
/// Copyright(c) crdx
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// https://raw.githubusercontent.com/crdx/PortableSettingsProvider
|
||||
///
|
||||
using System.Linq;
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright(c) crdx
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// https://raw.githubusercontent.com/crdx/PortableSettingsProvider
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections.Specialized;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
//using mRemoteNG.App;
|
||||
|
||||
namespace mRemoteNG.Config.Settings.Providers
|
||||
{
|
||||
@@ -43,63 +43,34 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
private const string _className = "PortableSettingsProvider";
|
||||
private XmlDocument _xmlDocument;
|
||||
|
||||
private string _filePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),
|
||||
string.Format("{0}.settings", ApplicationName));
|
||||
}
|
||||
}
|
||||
private string _filePath => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? throw new InvalidOperationException(), $"{ApplicationName}.settings");
|
||||
|
||||
private XmlNode _localSettingsNode
|
||||
{
|
||||
get
|
||||
{
|
||||
XmlNode settingsNode = GetSettingsNode(_localSettingsNodeName);
|
||||
XmlNode machineNode = settingsNode.SelectSingleNode(Environment.MachineName.ToLowerInvariant());
|
||||
private XmlNode _localSettingsNode => GetSettingsNode(_localSettingsNodeName);
|
||||
|
||||
if (machineNode == null)
|
||||
{
|
||||
machineNode = _rootDocument.CreateElement(Environment.MachineName.ToLowerInvariant());
|
||||
settingsNode.AppendChild(machineNode);
|
||||
}
|
||||
private XmlNode _globalSettingsNode => GetSettingsNode(_globalSettingsNodeName);
|
||||
|
||||
return machineNode;
|
||||
}
|
||||
}
|
||||
|
||||
private XmlNode _globalSettingsNode
|
||||
{
|
||||
get { return GetSettingsNode(_globalSettingsNodeName); }
|
||||
}
|
||||
|
||||
private XmlNode _rootNode
|
||||
{
|
||||
get { return _rootDocument.SelectSingleNode(_rootNodeName); }
|
||||
}
|
||||
private XmlNode _rootNode => _rootDocument.SelectSingleNode(_rootNodeName);
|
||||
|
||||
private XmlDocument _rootDocument
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_xmlDocument == null)
|
||||
if (_xmlDocument != null) return _xmlDocument;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
_xmlDocument = new XmlDocument();
|
||||
_xmlDocument.Load(_filePath);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (_xmlDocument.SelectSingleNode(_rootNodeName) != null)
|
||||
return _xmlDocument;
|
||||
|
||||
_xmlDocument = GetBlankXmlDocument();
|
||||
_xmlDocument = new XmlDocument();
|
||||
_xmlDocument.Load(_filePath);
|
||||
}
|
||||
catch (Exception /*ex*/)
|
||||
{
|
||||
// This casues hundreds of unit tests to fail for some reason...
|
||||
//Runtime.MessageCollector.AddExceptionStackTrace("PortableSettingsProvider: Error getting XML", ex);
|
||||
}
|
||||
|
||||
if (_xmlDocument?.SelectSingleNode(_rootNodeName) != null)
|
||||
return _xmlDocument;
|
||||
|
||||
_xmlDocument = GetBlankXmlDocument();
|
||||
|
||||
return _xmlDocument;
|
||||
}
|
||||
@@ -107,14 +78,11 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
public override string ApplicationName
|
||||
{
|
||||
get { return Path.GetFileNameWithoutExtension(Application.ExecutablePath); }
|
||||
get => Path.GetFileNameWithoutExtension(Application.ExecutablePath);
|
||||
set { }
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return _className; }
|
||||
}
|
||||
public override string Name => _className;
|
||||
|
||||
public override void Initialize(string name, NameValueCollection config)
|
||||
{
|
||||
@@ -143,7 +111,7 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
|
||||
{
|
||||
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
|
||||
var values = new SettingsPropertyValueCollection();
|
||||
|
||||
foreach (SettingsProperty property in collection)
|
||||
{
|
||||
@@ -158,11 +126,9 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
private void SetValue(SettingsPropertyValue propertyValue)
|
||||
{
|
||||
XmlNode targetNode = IsGlobal(propertyValue.Property)
|
||||
? _globalSettingsNode
|
||||
: _localSettingsNode;
|
||||
var targetNode = IsGlobal(propertyValue.Property) ? _globalSettingsNode : _localSettingsNode;
|
||||
|
||||
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", propertyValue.Name));
|
||||
var settingNode = targetNode.SelectSingleNode($"setting[@name='{propertyValue.Name}']");
|
||||
|
||||
if (settingNode != null)
|
||||
settingNode.InnerText = propertyValue.SerializedValue.ToString();
|
||||
@@ -170,10 +136,10 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
{
|
||||
settingNode = _rootDocument.CreateElement("setting");
|
||||
|
||||
XmlAttribute nameAttribute = _rootDocument.CreateAttribute("name");
|
||||
var nameAttribute = _rootDocument.CreateAttribute("name");
|
||||
nameAttribute.Value = propertyValue.Name;
|
||||
|
||||
settingNode.Attributes.Append(nameAttribute);
|
||||
settingNode.Attributes?.Append(nameAttribute);
|
||||
settingNode.InnerText = propertyValue.SerializedValue.ToString();
|
||||
|
||||
targetNode.AppendChild(settingNode);
|
||||
@@ -182,8 +148,8 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
private string GetValue(SettingsProperty property)
|
||||
{
|
||||
XmlNode targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode;
|
||||
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", property.Name));
|
||||
var targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode;
|
||||
var settingNode = targetNode.SelectSingleNode($"setting[@name='{property.Name}']");
|
||||
|
||||
if (settingNode == null)
|
||||
return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty;
|
||||
@@ -191,7 +157,7 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
return settingNode.InnerText;
|
||||
}
|
||||
|
||||
private bool IsGlobal(SettingsProperty property)
|
||||
private static bool IsGlobal(SettingsProperty property)
|
||||
{
|
||||
foreach (DictionaryEntry attribute in property.Attributes)
|
||||
{
|
||||
@@ -204,20 +170,18 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
private XmlNode GetSettingsNode(string name)
|
||||
{
|
||||
XmlNode settingsNode = _rootNode.SelectSingleNode(name);
|
||||
var settingsNode = _rootNode.SelectSingleNode(name);
|
||||
|
||||
if (settingsNode == null)
|
||||
{
|
||||
settingsNode = _rootDocument.CreateElement(name);
|
||||
_rootNode.AppendChild(settingsNode);
|
||||
}
|
||||
if (settingsNode != null) return settingsNode;
|
||||
settingsNode = _rootDocument.CreateElement(name);
|
||||
_rootNode.AppendChild(settingsNode);
|
||||
|
||||
return settingsNode;
|
||||
}
|
||||
|
||||
public XmlDocument GetBlankXmlDocument()
|
||||
private static XmlDocument GetBlankXmlDocument()
|
||||
{
|
||||
XmlDocument blankXmlDocument = new XmlDocument();
|
||||
var blankXmlDocument = new XmlDocument();
|
||||
blankXmlDocument.AppendChild(blankXmlDocument.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
|
||||
blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName));
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace mRemoteNG.Config.Settings
|
||||
{
|
||||
private readonly ExternalAppsLoader _externalAppsLoader;
|
||||
private readonly MessageCollector _messageCollector;
|
||||
private readonly MenuStrip _mainMenu;
|
||||
private readonly QuickConnectToolStrip _quickConnectToolStrip;
|
||||
private readonly ExternalToolsToolStrip _externalToolsToolStrip;
|
||||
private readonly MultiSshToolStrip _multiSshToolStrip;
|
||||
@@ -31,7 +32,8 @@ namespace mRemoteNG.Config.Settings
|
||||
MessageCollector messageCollector,
|
||||
QuickConnectToolStrip quickConnectToolStrip,
|
||||
ExternalToolsToolStrip externalToolsToolStrip,
|
||||
MultiSshToolStrip multiSshToolStrip)
|
||||
MultiSshToolStrip multiSshToolStrip,
|
||||
MenuStrip mainMenu)
|
||||
{
|
||||
if (mainForm == null)
|
||||
throw new ArgumentNullException(nameof(mainForm));
|
||||
@@ -43,13 +45,16 @@ namespace mRemoteNG.Config.Settings
|
||||
throw new ArgumentNullException(nameof(externalToolsToolStrip));
|
||||
if (multiSshToolStrip == null)
|
||||
throw new ArgumentNullException(nameof(multiSshToolStrip));
|
||||
if (mainMenu == null)
|
||||
throw new ArgumentNullException(nameof(mainMenu));
|
||||
|
||||
MainForm = mainForm;
|
||||
_messageCollector = messageCollector;
|
||||
_quickConnectToolStrip = quickConnectToolStrip;
|
||||
_externalToolsToolStrip = externalToolsToolStrip;
|
||||
_multiSshToolStrip = multiSshToolStrip;
|
||||
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
|
||||
_mainMenu = mainMenu;
|
||||
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
@@ -197,6 +202,7 @@ namespace mRemoteNG.Config.Settings
|
||||
private void LoadToolbarsFromSettings()
|
||||
{
|
||||
ResetAllToolbarLocations();
|
||||
AddMainMenuPanel();
|
||||
AddExternalAppsPanel();
|
||||
AddQuickConnectPanel();
|
||||
AddMultiSshPanel();
|
||||
@@ -210,31 +216,49 @@ namespace mRemoteNG.Config.Settings
|
||||
private void ResetAllToolbarLocations()
|
||||
{
|
||||
var tempToolStrip = new ToolStripPanel();
|
||||
tempToolStrip.Join(_mainMenu);
|
||||
tempToolStrip.Join(_quickConnectToolStrip);
|
||||
tempToolStrip.Join(_externalToolsToolStrip);
|
||||
tempToolStrip.Join(_multiSshToolStrip);
|
||||
}
|
||||
|
||||
private void AddMainMenuPanel()
|
||||
{
|
||||
SetToolstripGripStyle(_mainMenu);
|
||||
var toolStripPanel = ToolStripPanelFromString("top");
|
||||
toolStripPanel.Join(_mainMenu, new Point(3, 0));
|
||||
}
|
||||
|
||||
private void AddQuickConnectPanel()
|
||||
{
|
||||
SetToolstripGripStyle(_quickConnectToolStrip);
|
||||
_quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible;
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.QuickyTBParentDock);
|
||||
toolStripPanel.Join(_quickConnectToolStrip, mRemoteNG.Settings.Default.QuickyTBLocation);
|
||||
_quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible;
|
||||
}
|
||||
|
||||
private void AddExternalAppsPanel()
|
||||
{
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
|
||||
toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation);
|
||||
SetToolstripGripStyle(_externalToolsToolStrip);
|
||||
_externalToolsToolStrip.Visible = mRemoteNG.Settings.Default.ExtAppsTBVisible;
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
|
||||
toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation);
|
||||
}
|
||||
|
||||
private void AddMultiSshPanel()
|
||||
{
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
|
||||
toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation);
|
||||
SetToolstripGripStyle(_multiSshToolStrip);
|
||||
_multiSshToolStrip.Visible = mRemoteNG.Settings.Default.MultiSshToolbarVisible;
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.MultiSshToolbarParentDock);
|
||||
toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation);
|
||||
}
|
||||
|
||||
private void SetToolstripGripStyle(ToolStrip toolbar)
|
||||
{
|
||||
toolbar.GripStyle = mRemoteNG.Settings.Default.LockToolbars
|
||||
? ToolStripGripStyle.Hidden
|
||||
: ToolStripGripStyle.Visible;
|
||||
}
|
||||
|
||||
private ToolStripPanel ToolStripPanelFromString(string panel)
|
||||
{
|
||||
|
||||
@@ -87,8 +87,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")]
|
||||
public virtual string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetField(ref _name, value, "Name"); }
|
||||
get => _name;
|
||||
set => SetField(ref _name, value, "Name");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
|
||||
@@ -96,8 +96,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDescription")]
|
||||
public virtual string Description
|
||||
{
|
||||
get { return GetPropertyValue("Description", _description); }
|
||||
set { SetField(ref _description, value, "Description"); }
|
||||
get => GetPropertyValue("Description", _description);
|
||||
set => SetField(ref _description, value, "Description");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
|
||||
@@ -106,8 +106,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionIcon")]
|
||||
public virtual string Icon
|
||||
{
|
||||
get { return GetPropertyValue("Icon", _icon); }
|
||||
set { SetField(ref _icon, value, "Icon"); }
|
||||
get => GetPropertyValue("Icon", _icon);
|
||||
set => SetField(ref _icon, value, "Icon");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
|
||||
@@ -115,8 +115,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")]
|
||||
public virtual string Panel
|
||||
{
|
||||
get { return GetPropertyValue("Panel", _panel); }
|
||||
set { SetField(ref _panel, value, "Panel"); }
|
||||
get => GetPropertyValue("Panel", _panel);
|
||||
set => SetField(ref _panel, value, "Panel");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -126,8 +126,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAddress")]
|
||||
public virtual string Hostname
|
||||
{
|
||||
get { return _hostname.Trim(); }
|
||||
set { SetField(ref _hostname, value?.Trim(), "Hostname"); }
|
||||
get => _hostname.Trim();
|
||||
set => SetField(ref _hostname, value?.Trim(), "Hostname");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -135,8 +135,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUsername")]
|
||||
public virtual string Username
|
||||
{
|
||||
get { return GetPropertyValue("Username", _username); }
|
||||
set { SetField(ref _username, value?.Trim(), "Username"); }
|
||||
get => GetPropertyValue("Username", _username);
|
||||
set => SetField(ref _username, value?.Trim(), "Username");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -145,8 +145,8 @@ namespace mRemoteNG.Connection
|
||||
PasswordPropertyText(true)]
|
||||
public virtual string Password
|
||||
{
|
||||
get { return GetPropertyValue("Password", _password); }
|
||||
set { SetField(ref _password, value, "Password"); }
|
||||
get => GetPropertyValue("Password", _password);
|
||||
set => SetField(ref _password, value, "Password");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -154,8 +154,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDomain")]
|
||||
public string Domain
|
||||
{
|
||||
get { return GetPropertyValue("Domain", _domain).Trim(); }
|
||||
set { SetField(ref _domain, value?.Trim(), "Domain"); }
|
||||
get => GetPropertyValue("Domain", _domain).Trim();
|
||||
set => SetField(ref _domain, value?.Trim(), "Domain");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -166,8 +166,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public virtual ProtocolType Protocol
|
||||
{
|
||||
get { return GetPropertyValue("Protocol", _protocol); }
|
||||
set { SetField(ref _protocol, value, "Protocol"); }
|
||||
get => GetPropertyValue("Protocol", _protocol);
|
||||
set => SetField(ref _protocol, value, "Protocol");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -176,8 +176,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(ExternalToolsTypeConverter))]
|
||||
public string ExtApp
|
||||
{
|
||||
get { return GetPropertyValue("ExtApp", _extApp); }
|
||||
set { SetField(ref _extApp, value, "ExtApp"); }
|
||||
get => GetPropertyValue("ExtApp", _extApp);
|
||||
set => SetField(ref _extApp, value, "ExtApp");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -185,8 +185,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPort")]
|
||||
public virtual int Port
|
||||
{
|
||||
get { return GetPropertyValue("Port", _port); }
|
||||
set { SetField(ref _port, value, "Port"); }
|
||||
get => GetPropertyValue("Port", _port);
|
||||
set => SetField(ref _port, value, "Port");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -195,8 +195,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(Config.Putty.PuttySessionsManager.SessionList))]
|
||||
public virtual string PuttySession
|
||||
{
|
||||
get { return GetPropertyValue("PuttySession", _puttySession); }
|
||||
set { SetField(ref _puttySession, value, "PuttySession"); }
|
||||
get => GetPropertyValue("PuttySession", _puttySession);
|
||||
set => SetField(ref _puttySession, value, "PuttySession");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -205,8 +205,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public IcaProtocol.EncryptionStrength ICAEncryptionStrength
|
||||
{
|
||||
get { return GetPropertyValue("ICAEncryptionStrength", _icaEncryption); }
|
||||
set { SetField(ref _icaEncryption, value, "ICAEncryptionStrength"); }
|
||||
get => GetPropertyValue("ICAEncryptionStrength", _icaEncryption);
|
||||
set => SetField(ref _icaEncryption, value, "ICAEncryptionStrength");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -215,8 +215,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool UseConsoleSession
|
||||
{
|
||||
get { return GetPropertyValue("UseConsoleSession", _useConsoleSession); }
|
||||
set { SetField(ref _useConsoleSession, value, "UseConsoleSession"); }
|
||||
get => GetPropertyValue("UseConsoleSession", _useConsoleSession);
|
||||
set => SetField(ref _useConsoleSession, value, "UseConsoleSession");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -225,8 +225,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.AuthenticationLevel RDPAuthenticationLevel
|
||||
{
|
||||
get { return GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel); }
|
||||
set { SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel"); }
|
||||
get => GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel);
|
||||
set => SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -234,7 +234,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")]
|
||||
public virtual int RDPMinutesToIdleTimeout
|
||||
{
|
||||
get { return GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); }
|
||||
get => GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout);
|
||||
set {
|
||||
if(value < 0)
|
||||
value = 0;
|
||||
@@ -249,8 +249,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")]
|
||||
public bool RDPAlertIdleTimeout
|
||||
{
|
||||
get { return GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); }
|
||||
set { SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout"); }
|
||||
get => GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout);
|
||||
set => SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -258,8 +258,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")]
|
||||
public string LoadBalanceInfo
|
||||
{
|
||||
get { return GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim(); }
|
||||
set { SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo"); }
|
||||
get => GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim();
|
||||
set => SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -268,8 +268,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public HTTPBase.RenderingEngine RenderingEngine
|
||||
{
|
||||
get { return GetPropertyValue("RenderingEngine", _renderingEngine); }
|
||||
set { SetField(ref _renderingEngine, value, "RenderingEngine"); }
|
||||
get => GetPropertyValue("RenderingEngine", _renderingEngine);
|
||||
set => SetField(ref _renderingEngine, value, "RenderingEngine");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -278,8 +278,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool UseCredSsp
|
||||
{
|
||||
get { return GetPropertyValue("UseCredSsp", _useCredSsp); }
|
||||
set { SetField(ref _useCredSsp, value, "UseCredSsp"); }
|
||||
get => GetPropertyValue("UseCredSsp", _useCredSsp);
|
||||
set => SetField(ref _useCredSsp, value, "UseCredSsp");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -290,8 +290,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDGatewayUsageMethod RDGatewayUsageMethod
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod); }
|
||||
set { SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod"); }
|
||||
get => GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod);
|
||||
set => SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -299,8 +299,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayHostname")]
|
||||
public string RDGatewayHostname
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim(); }
|
||||
set { SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname"); }
|
||||
get => GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim();
|
||||
set => SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -309,8 +309,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDGatewayUseConnectionCredentials RDGatewayUseConnectionCredentials
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials); }
|
||||
set { SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials"); }
|
||||
get => GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials);
|
||||
set => SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -318,8 +318,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")]
|
||||
public string RDGatewayUsername
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim(); }
|
||||
set { SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername"); }
|
||||
get => GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim();
|
||||
set => SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -328,8 +328,8 @@ namespace mRemoteNG.Connection
|
||||
PasswordPropertyText(true)]
|
||||
public string RDGatewayPassword
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayPassword", _rdGatewayPassword); }
|
||||
set { SetField(ref _rdGatewayPassword, value, "RDGatewayPassword"); }
|
||||
get => GetPropertyValue("RDGatewayPassword", _rdGatewayPassword);
|
||||
set => SetField(ref _rdGatewayPassword, value, "RDGatewayPassword");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -337,8 +337,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")]
|
||||
public string RDGatewayDomain
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim(); }
|
||||
set { SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain"); }
|
||||
get => GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim();
|
||||
set => SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -349,8 +349,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPResolutions Resolution
|
||||
{
|
||||
get { return GetPropertyValue("Resolution", _resolution); }
|
||||
set { SetField(ref _resolution, value, "Resolution"); }
|
||||
get => GetPropertyValue("Resolution", _resolution);
|
||||
set => SetField(ref _resolution, value, "Resolution");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -359,8 +359,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool AutomaticResize
|
||||
{
|
||||
get { return GetPropertyValue("AutomaticResize", _automaticResize); }
|
||||
set { SetField(ref _automaticResize, value, "AutomaticResize"); }
|
||||
get => GetPropertyValue("AutomaticResize", _automaticResize);
|
||||
set => SetField(ref _automaticResize, value, "AutomaticResize");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -369,8 +369,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPColors Colors
|
||||
{
|
||||
get { return GetPropertyValue("Colors", _colors); }
|
||||
set { SetField(ref _colors, value, "Colors"); }
|
||||
get => GetPropertyValue("Colors", _colors);
|
||||
set => SetField(ref _colors, value, "Colors");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -379,8 +379,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool CacheBitmaps
|
||||
{
|
||||
get { return GetPropertyValue("CacheBitmaps", _cacheBitmaps); }
|
||||
set { SetField(ref _cacheBitmaps, value, "CacheBitmaps"); }
|
||||
get => GetPropertyValue("CacheBitmaps", _cacheBitmaps);
|
||||
set => SetField(ref _cacheBitmaps, value, "CacheBitmaps");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -389,8 +389,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool DisplayWallpaper
|
||||
{
|
||||
get { return GetPropertyValue("DisplayWallpaper", _displayWallpaper); }
|
||||
set { SetField(ref _displayWallpaper, value, "DisplayWallpaper"); }
|
||||
get => GetPropertyValue("DisplayWallpaper", _displayWallpaper);
|
||||
set => SetField(ref _displayWallpaper, value, "DisplayWallpaper");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -399,8 +399,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool DisplayThemes
|
||||
{
|
||||
get { return GetPropertyValue("DisplayThemes", _displayThemes); }
|
||||
set { SetField(ref _displayThemes, value, "DisplayThemes"); }
|
||||
get => GetPropertyValue("DisplayThemes", _displayThemes);
|
||||
set => SetField(ref _displayThemes, value, "DisplayThemes");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -409,8 +409,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool EnableFontSmoothing
|
||||
{
|
||||
get { return GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing); }
|
||||
set { SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing"); }
|
||||
get => GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing);
|
||||
set => SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -419,8 +419,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool EnableDesktopComposition
|
||||
{
|
||||
get { return GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition); }
|
||||
set { SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition"); }
|
||||
get => GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition);
|
||||
set => SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -431,8 +431,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectKeys
|
||||
{
|
||||
get { return GetPropertyValue("RedirectKeys", _redirectKeys); }
|
||||
set { SetField(ref _redirectKeys, value, "RedirectKeys"); }
|
||||
get => GetPropertyValue("RedirectKeys", _redirectKeys);
|
||||
set => SetField(ref _redirectKeys, value, "RedirectKeys");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -441,8 +441,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectDiskDrives
|
||||
{
|
||||
get { return GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives); }
|
||||
set { SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives"); }
|
||||
get => GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives);
|
||||
set => SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -451,8 +451,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectPrinters
|
||||
{
|
||||
get { return GetPropertyValue("RedirectPrinters", _redirectPrinters); }
|
||||
set { SetField(ref _redirectPrinters, value, "RedirectPrinters"); }
|
||||
get => GetPropertyValue("RedirectPrinters", _redirectPrinters);
|
||||
set => SetField(ref _redirectPrinters, value, "RedirectPrinters");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -461,8 +461,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectPorts
|
||||
{
|
||||
get { return GetPropertyValue("RedirectPorts", _redirectPorts); }
|
||||
set { SetField(ref _redirectPorts, value, "RedirectPorts"); }
|
||||
get => GetPropertyValue("RedirectPorts", _redirectPorts);
|
||||
set => SetField(ref _redirectPorts, value, "RedirectPorts");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -471,8 +471,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectSmartCards
|
||||
{
|
||||
get { return GetPropertyValue("RedirectSmartCards", _redirectSmartCards); }
|
||||
set { SetField(ref _redirectSmartCards, value, "RedirectSmartCards"); }
|
||||
get => GetPropertyValue("RedirectSmartCards", _redirectSmartCards);
|
||||
set => SetField(ref _redirectSmartCards, value, "RedirectSmartCards");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -481,8 +481,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPSounds RedirectSound
|
||||
{
|
||||
get { return GetPropertyValue("RedirectSound", _redirectSound); }
|
||||
set { SetField(ref _redirectSound, value, "RedirectSound"); }
|
||||
get => GetPropertyValue("RedirectSound", _redirectSound);
|
||||
set => SetField(ref _redirectSound, value, "RedirectSound");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -491,8 +491,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPSoundQuality SoundQuality
|
||||
{
|
||||
get { return GetPropertyValue("SoundQuality", _soundQuality); }
|
||||
set { SetField(ref _soundQuality, value, "SoundQuality"); }
|
||||
get => GetPropertyValue("SoundQuality", _soundQuality);
|
||||
set => SetField(ref _soundQuality, value, "SoundQuality");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -506,8 +506,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(ExternalToolsTypeConverter))]
|
||||
public virtual string PreExtApp
|
||||
{
|
||||
get { return GetPropertyValue("PreExtApp", _preExtApp); }
|
||||
set { SetField(ref _preExtApp, value, "PreExtApp"); }
|
||||
get => GetPropertyValue("PreExtApp", _preExtApp);
|
||||
set => SetField(ref _preExtApp, value, "PreExtApp");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -516,8 +516,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(ExternalToolsTypeConverter))]
|
||||
public virtual string PostExtApp
|
||||
{
|
||||
get { return GetPropertyValue("PostExtApp", _postExtApp); }
|
||||
set { SetField(ref _postExtApp, value, "PostExtApp"); }
|
||||
get => GetPropertyValue("PostExtApp", _postExtApp);
|
||||
set => SetField(ref _postExtApp, value, "PostExtApp");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -525,8 +525,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionMACAddress")]
|
||||
public virtual string MacAddress
|
||||
{
|
||||
get { return GetPropertyValue("MacAddress", _macAddress); }
|
||||
set { SetField(ref _macAddress, value, "MacAddress"); }
|
||||
get => GetPropertyValue("MacAddress", _macAddress);
|
||||
set => SetField(ref _macAddress, value, "MacAddress");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -534,8 +534,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUser1")]
|
||||
public virtual string UserField
|
||||
{
|
||||
get { return GetPropertyValue("UserField", _userField); }
|
||||
set { SetField(ref _userField, value, "UserField"); }
|
||||
get => GetPropertyValue("UserField", _userField);
|
||||
set => SetField(ref _userField, value, "UserField");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -547,8 +547,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.Compression VNCCompression
|
||||
{
|
||||
get { return GetPropertyValue("VNCCompression", _vncCompression); }
|
||||
set { SetField(ref _vncCompression, value, "VNCCompression"); }
|
||||
get => GetPropertyValue("VNCCompression", _vncCompression);
|
||||
set => SetField(ref _vncCompression, value, "VNCCompression");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -558,8 +558,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.Encoding VNCEncoding
|
||||
{
|
||||
get { return GetPropertyValue("VNCEncoding", _vncEncoding); }
|
||||
set { SetField(ref _vncEncoding, value, "VNCEncoding"); }
|
||||
get => GetPropertyValue("VNCEncoding", _vncEncoding);
|
||||
set => SetField(ref _vncEncoding, value, "VNCEncoding");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -569,8 +569,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.AuthMode VNCAuthMode
|
||||
{
|
||||
get { return GetPropertyValue("VNCAuthMode", _vncAuthMode); }
|
||||
set { SetField(ref _vncAuthMode, value, "VNCAuthMode"); }
|
||||
get => GetPropertyValue("VNCAuthMode", _vncAuthMode);
|
||||
set => SetField(ref _vncAuthMode, value, "VNCAuthMode");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -580,8 +580,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.ProxyType VNCProxyType
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyType", _vncProxyType); }
|
||||
set { SetField(ref _vncProxyType, value, "VNCProxyType"); }
|
||||
get => GetPropertyValue("VNCProxyType", _vncProxyType);
|
||||
set => SetField(ref _vncProxyType, value, "VNCProxyType");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -590,8 +590,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyAddress")]
|
||||
public string VNCProxyIP
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyIP", _vncProxyIp); }
|
||||
set { SetField(ref _vncProxyIp, value, "VNCProxyIP"); }
|
||||
get => GetPropertyValue("VNCProxyIP", _vncProxyIp);
|
||||
set => SetField(ref _vncProxyIp, value, "VNCProxyIP");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -600,8 +600,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPort")]
|
||||
public int VNCProxyPort
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyPort", _vncProxyPort); }
|
||||
set { SetField(ref _vncProxyPort, value, "VNCProxyPort"); }
|
||||
get => GetPropertyValue("VNCProxyPort", _vncProxyPort);
|
||||
set => SetField(ref _vncProxyPort, value, "VNCProxyPort");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -610,8 +610,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")]
|
||||
public string VNCProxyUsername
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyUsername", _vncProxyUsername); }
|
||||
set { SetField(ref _vncProxyUsername, value, "VNCProxyUsername"); }
|
||||
get => GetPropertyValue("VNCProxyUsername", _vncProxyUsername);
|
||||
set => SetField(ref _vncProxyUsername, value, "VNCProxyUsername");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -621,8 +621,8 @@ namespace mRemoteNG.Connection
|
||||
PasswordPropertyText(true)]
|
||||
public string VNCProxyPassword
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyPassword", _vncProxyPassword); }
|
||||
set { SetField(ref _vncProxyPassword, value, "VNCProxyPassword"); }
|
||||
get => GetPropertyValue("VNCProxyPassword", _vncProxyPassword);
|
||||
set => SetField(ref _vncProxyPassword, value, "VNCProxyPassword");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -632,8 +632,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.Colors VNCColors
|
||||
{
|
||||
get { return GetPropertyValue("VNCColors", _vncColors); }
|
||||
set { SetField(ref _vncColors, value, "VNCColors"); }
|
||||
get => GetPropertyValue("VNCColors", _vncColors);
|
||||
set => SetField(ref _vncColors, value, "VNCColors");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -642,8 +642,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.SmartSizeMode VNCSmartSizeMode
|
||||
{
|
||||
get { return GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode); }
|
||||
set { SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode"); }
|
||||
get => GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode);
|
||||
set => SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -652,8 +652,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool VNCViewOnly
|
||||
{
|
||||
get { return GetPropertyValue("VNCViewOnly", _vncViewOnly); }
|
||||
set { SetField(ref _vncViewOnly, value, "VNCViewOnly"); }
|
||||
get => GetPropertyValue("VNCViewOnly", _vncViewOnly);
|
||||
set => SetField(ref _vncViewOnly, value, "VNCViewOnly");
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
@@ -665,7 +665,7 @@ namespace mRemoteNG.Connection
|
||||
|
||||
protected virtual TPropertyType GetPropertyValue<TPropertyType>(string propertyName, TPropertyType value)
|
||||
{
|
||||
return (TPropertyType)GetType().GetProperty(propertyName).GetValue(this, null);
|
||||
return (TPropertyType)GetType().GetProperty(propertyName)?.GetValue(this, null);
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
@@ -674,12 +674,11 @@ namespace mRemoteNG.Connection
|
||||
PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(args.PropertyName));
|
||||
}
|
||||
|
||||
protected bool SetField<T>(ref T field, T value, string propertyName = null)
|
||||
private void SetField<T>(ref T field, T value, string propertyName = null)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) return;
|
||||
field = value;
|
||||
RaisePropertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
@@ -15,11 +10,16 @@ using mRemoteNG.Connection.Protocol.Telnet;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
[DefaultProperty("Name")]
|
||||
[DefaultProperty("Name")]
|
||||
public class ConnectionInfo : AbstractConnectionRecord, IHasParent, IInheritable
|
||||
{
|
||||
#region Public Properties
|
||||
@@ -78,7 +78,8 @@ namespace mRemoteNG.Connection
|
||||
var newConnectionInfo = new ConnectionInfo();
|
||||
newConnectionInfo.CopyFrom(this);
|
||||
newConnectionInfo.Inheritance = Inheritance.Clone();
|
||||
return newConnectionInfo;
|
||||
newConnectionInfo.Inheritance.Parent = newConnectionInfo;
|
||||
return newConnectionInfo;
|
||||
}
|
||||
|
||||
public void CopyFrom(ConnectionInfo sourceConnectionInfo)
|
||||
@@ -172,10 +173,11 @@ namespace mRemoteNG.Connection
|
||||
if (!ShouldThisPropertyBeInherited(propertyName))
|
||||
return value;
|
||||
|
||||
var inheritedValue = GetInheritedPropertyValue<TPropertyType>(propertyName);
|
||||
if (inheritedValue.Equals(default(TPropertyType)))
|
||||
return value;
|
||||
return inheritedValue;
|
||||
var couldGetInheritedValue = TryGetInheritedPropertyValue<TPropertyType>(propertyName, out var inheritedValue);
|
||||
|
||||
return couldGetInheritedValue
|
||||
? inheritedValue
|
||||
: value;
|
||||
}
|
||||
|
||||
private bool ShouldThisPropertyBeInherited(string propertyName)
|
||||
@@ -196,22 +198,23 @@ namespace mRemoteNG.Connection
|
||||
return inheritPropertyValue;
|
||||
}
|
||||
|
||||
private TPropertyType GetInheritedPropertyValue<TPropertyType>(string propertyName)
|
||||
private bool TryGetInheritedPropertyValue<TPropertyType>(string propertyName, out TPropertyType inheritedValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var connectionInfoType = Parent.GetType();
|
||||
var parentPropertyInfo = connectionInfoType.GetProperty(propertyName);
|
||||
if (parentPropertyInfo == null)
|
||||
return default(TPropertyType); // shouldn't get here...
|
||||
var parentPropertyValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
|
||||
throw new NullReferenceException($"Could not retrieve property data for property '{propertyName}' on parent node '{Parent?.Name}'");
|
||||
|
||||
return parentPropertyValue;
|
||||
inheritedValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionStackTrace($"Error retrieving inherited property '{propertyName}'", e);
|
||||
return default(TPropertyType);
|
||||
inheritedValue = default(TPropertyType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace mRemoteNG.Connection
|
||||
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
|
||||
|
||||
var connectionPanel = SetConnectionPanel(connectionInfo, force);
|
||||
if (string.IsNullOrEmpty(connectionPanel)) return;
|
||||
var connectionForm = SetConnectionForm(conForm, connectionPanel);
|
||||
var connectionContainer = SetConnectionContainer(connectionInfo, connectionForm);
|
||||
SetConnectionFormEventHandlers(newProtocol, connectionForm);
|
||||
@@ -163,6 +164,10 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
connectionPanel = frmPnl.Panel;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -8,10 +8,12 @@ using mRemoteNG.Config.Connections;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI;
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
@@ -19,6 +21,9 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
private static readonly object SaveLock = new object();
|
||||
private readonly PuttySessionsManager _puttySessionsManager;
|
||||
private bool _batchingSaves = false;
|
||||
private bool _saveRequested = false;
|
||||
private bool _saveAsyncRequested = false;
|
||||
|
||||
public bool IsConnectionsFileLoaded { get; set; }
|
||||
public bool UsingDatabase { get; private set; }
|
||||
@@ -27,11 +32,6 @@ namespace mRemoteNG.Connection
|
||||
public DateTime LastSqlUpdate { get; set; }
|
||||
|
||||
public ConnectionTreeModel ConnectionTreeModel { get; private set; }
|
||||
//public ConnectionTreeModel ConnectionTreeModel
|
||||
//{
|
||||
// get { return Windows.TreeForm.ConnectionTree.ConnectionTreeModel; }
|
||||
// set { Windows.TreeForm.ConnectionTree.ConnectionTreeModel = value; }
|
||||
//}
|
||||
|
||||
public ConnectionsService(PuttySessionsManager puttySessionsManager)
|
||||
{
|
||||
@@ -45,11 +45,11 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
try
|
||||
{
|
||||
filename.ThrowIfNullOrEmpty(nameof(filename));
|
||||
var newConnectionsModel = new ConnectionTreeModel();
|
||||
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
|
||||
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename);
|
||||
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
|
||||
LoadConnections(false, false, filename);
|
||||
UpdateCustomConsPathSetting(filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -79,6 +79,10 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
newConnectionInfo.Port = uri.Port;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(newConnectionInfo.Panel))
|
||||
newConnectionInfo.Panel = Language.strGeneral;
|
||||
|
||||
newConnectionInfo.IsQuickConnect = true;
|
||||
|
||||
return newConnectionInfo;
|
||||
@@ -97,16 +101,24 @@ namespace mRemoteNG.Connection
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="import"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
public ConnectionTreeModel LoadConnections(bool useDatabase, bool import, string connectionFileName)
|
||||
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
|
||||
{
|
||||
var oldConnectionTreeModel = ConnectionTreeModel;
|
||||
var oldIsUsingDatabaseValue = UsingDatabase;
|
||||
|
||||
var newConnectionTreeModel =
|
||||
(useDatabase
|
||||
? new SqlConnectionsLoader().Load()
|
||||
: new XmlConnectionsLoader(connectionFileName).Load())
|
||||
?? new ConnectionTreeModel();
|
||||
var newConnectionTreeModel = useDatabase
|
||||
? new SqlConnectionsLoader().Load()
|
||||
: new XmlConnectionsLoader(connectionFileName).Load();
|
||||
|
||||
if (newConnectionTreeModel == null)
|
||||
{
|
||||
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded);
|
||||
return;
|
||||
}
|
||||
|
||||
IsConnectionsFileLoaded = true;
|
||||
ConnectionFileName = connectionFileName;
|
||||
UsingDatabase = useDatabase;
|
||||
|
||||
if (!import)
|
||||
{
|
||||
@@ -114,12 +126,35 @@ namespace mRemoteNG.Connection
|
||||
newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes);
|
||||
}
|
||||
|
||||
IsConnectionsFileLoaded = true;
|
||||
ConnectionFileName = connectionFileName;
|
||||
UsingDatabase = useDatabase;
|
||||
ConnectionTreeModel = newConnectionTreeModel;
|
||||
UpdateCustomConsPathSetting(connectionFileName);
|
||||
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, useDatabase, connectionFileName);
|
||||
return newConnectionTreeModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When turned on, calls to <see cref="SaveConnections()"/> or
|
||||
/// <see cref="SaveConnectionsAsync"/> will not immediately execute.
|
||||
/// Instead, they will be deferred until <see cref="EndBatchingSaves"/>
|
||||
/// is called.
|
||||
/// </summary>
|
||||
public void BeginBatchingSaves()
|
||||
{
|
||||
_batchingSaves = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately executes a single <see cref="SaveConnections()"/> or
|
||||
/// <see cref="SaveConnectionsAsync"/> if one has been requested
|
||||
/// since calling <see cref="BeginBatchingSaves"/>.
|
||||
/// </summary>
|
||||
public void EndBatchingSaves()
|
||||
{
|
||||
_batchingSaves = false;
|
||||
|
||||
if (_saveAsyncRequested)
|
||||
SaveConnectionsAsync();
|
||||
else if(_saveRequested)
|
||||
SaveConnections();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -128,8 +163,6 @@ namespace mRemoteNG.Connection
|
||||
/// </summary>
|
||||
public void SaveConnections()
|
||||
{
|
||||
if (!IsConnectionsFileLoaded)
|
||||
return;
|
||||
SaveConnections(ConnectionTreeModel, UsingDatabase, new SaveFilter(), ConnectionFileName);
|
||||
}
|
||||
|
||||
@@ -141,12 +174,24 @@ namespace mRemoteNG.Connection
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="saveFilter"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName)
|
||||
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
|
||||
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName, bool forceSave = false)
|
||||
{
|
||||
if (connectionTreeModel == null) return;
|
||||
if (connectionTreeModel == null)
|
||||
return;
|
||||
|
||||
if (!forceSave && !IsConnectionsFileLoaded)
|
||||
return;
|
||||
|
||||
if (_batchingSaves)
|
||||
{
|
||||
_saveRequested = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Saving connections...");
|
||||
RemoteConnectionsSyncronizer?.Disable();
|
||||
|
||||
var previouslyUsingDatabase = UsingDatabase;
|
||||
@@ -161,6 +206,7 @@ namespace mRemoteNG.Connection
|
||||
UsingDatabase = useDatabase;
|
||||
ConnectionFileName = connectionFileName;
|
||||
RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, connectionFileName);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Successfully saved connections");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -174,6 +220,12 @@ namespace mRemoteNG.Connection
|
||||
|
||||
public void SaveConnectionsAsync()
|
||||
{
|
||||
if (_batchingSaves)
|
||||
{
|
||||
_saveAsyncRequested = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var t = new Thread(SaveConnectionsBGd);
|
||||
t.SetApartmentState(ApartmentState.STA);
|
||||
t.Start();
|
||||
@@ -181,19 +233,24 @@ namespace mRemoteNG.Connection
|
||||
|
||||
private void SaveConnectionsBGd()
|
||||
{
|
||||
Monitor.Enter(SaveLock);
|
||||
SaveConnections();
|
||||
Monitor.Exit(SaveLock);
|
||||
lock (SaveLock)
|
||||
{
|
||||
SaveConnections();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetStartupConnectionFileName()
|
||||
{
|
||||
return Settings.Default.LoadConsFromCustomLocation == false ? GetDefaultStartupConnectionFileName() : Settings.Default.CustomConsPath;
|
||||
return Settings.Default.LoadConsFromCustomLocation == false
|
||||
? GetDefaultStartupConnectionFileName()
|
||||
: Settings.Default.CustomConsPath;
|
||||
}
|
||||
|
||||
public string GetDefaultStartupConnectionFileName()
|
||||
{
|
||||
return Runtime.IsPortableEdition ? GetDefaultStartupConnectionFileNamePortableEdition() : GetDefaultStartupConnectionFileNameNormalEdition();
|
||||
return Runtime.IsPortableEdition
|
||||
? GetDefaultStartupConnectionFileNamePortableEdition()
|
||||
: GetDefaultStartupConnectionFileNameNormalEdition();
|
||||
}
|
||||
|
||||
private void UpdateCustomConsPathSetting(string filename)
|
||||
|
||||
@@ -31,9 +31,14 @@ namespace mRemoteNG.Connection
|
||||
throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found.");
|
||||
|
||||
var valueFromSource = propertyFromSource.GetValue(sourceInstance, null);
|
||||
var value = Convert.ChangeType(valueFromSource, property.PropertyType);
|
||||
|
||||
if (property.PropertyType.IsEnum)
|
||||
{
|
||||
property.SetValue(Instance, Enum.Parse(property.PropertyType, valueFromSource.ToString()), null);
|
||||
continue;
|
||||
}
|
||||
|
||||
property.SetValue(Instance, value, null);
|
||||
property.SetValue(Instance, Convert.ChangeType(valueFromSource, property.PropertyType), null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -199,7 +199,14 @@ namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
return;
|
||||
}
|
||||
NativeMethods.MoveWindow(PuttyHandle, -SystemInformation.FrameBorderSize.Width, -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height), InterfaceControl.Width + SystemInformation.FrameBorderSize.Width * 2, InterfaceControl.Height + SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height * 2, true);
|
||||
|
||||
var left = -(SystemInformation.FrameBorderSize.Width + SystemInformation.HorizontalResizeBorderThickness);
|
||||
var top = -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height + SystemInformation.VerticalResizeBorderThickness);
|
||||
var width = InterfaceControl.Width + (SystemInformation.FrameBorderSize.Width + SystemInformation.HorizontalResizeBorderThickness) * 2;
|
||||
var height = InterfaceControl.Height + SystemInformation.CaptionHeight +
|
||||
(SystemInformation.FrameBorderSize.Height + SystemInformation.VerticalResizeBorderThickness) * 2;
|
||||
|
||||
NativeMethods.MoveWindow(PuttyHandle, left, top, width, height, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -316,10 +316,19 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
return;
|
||||
}
|
||||
|
||||
var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size;
|
||||
try
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Resizing RDP connection to host '{_connectionInfo.Hostname}'");
|
||||
var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size;
|
||||
|
||||
IMsRdpClient8 msRdpClient8 = _rdpClient;
|
||||
msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height);
|
||||
IMsRdpClient8 msRdpClient8 = _rdpClient;
|
||||
msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.ChangeConnectionResolutionError, _connectionInfo.Hostname),
|
||||
ex, MessageClass.WarningMsg, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRdGateway()
|
||||
@@ -916,17 +925,25 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
#region Reconnect Stuff
|
||||
public void tmrReconnect_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port));
|
||||
try
|
||||
{
|
||||
var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port));
|
||||
|
||||
ReconnectGroup.ServerReady = srvReady;
|
||||
ReconnectGroup.ServerReady = srvReady;
|
||||
|
||||
if (ReconnectGroup.ReconnectWhenReady && srvReady)
|
||||
{
|
||||
tmrReconnect.Enabled = false;
|
||||
ReconnectGroup.DisposeReconnectGroup();
|
||||
//SetProps()
|
||||
_rdpClient.Connect();
|
||||
}
|
||||
if (ReconnectGroup.ReconnectWhenReady && srvReady)
|
||||
{
|
||||
tmrReconnect.Enabled = false;
|
||||
ReconnectGroup.DisposeReconnectGroup();
|
||||
//SetProps()
|
||||
_rdpClient.Connect();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.AutomaticReconnectError, _connectionInfo.Hostname),
|
||||
ex, MessageClass.WarningMsg, false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace mRemoteNG.Connection
|
||||
connectionInfo.Hostname = url;
|
||||
connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP;
|
||||
connectionInfo.SetDefaultPort();
|
||||
if (string.IsNullOrEmpty(connectionInfo.Panel))
|
||||
connectionInfo.Panel = Language.strGeneral;
|
||||
connectionInfo.IsQuickConnect = true;
|
||||
var connectionInitiator = new ConnectionInitiator();
|
||||
connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Messages.MessageWriters;
|
||||
using mRemoteNG.UI.Forms;
|
||||
@@ -12,29 +13,21 @@ namespace mRemoteNG.Messages.WriterDecorators
|
||||
private readonly IMessageTypeFilteringOptions _filter;
|
||||
private readonly IMessageWriter _decoratedWriter;
|
||||
private readonly ErrorAndInfoWindow _messageWindow;
|
||||
private Timer _ecTimer;
|
||||
private readonly FrmMain _frmMain = FrmMain.Default;
|
||||
|
||||
public MessageFocusDecorator(ErrorAndInfoWindow messageWindow, IMessageTypeFilteringOptions filter, IMessageWriter decoratedWriter)
|
||||
{
|
||||
if (filter == null)
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
if (messageWindow == null)
|
||||
throw new ArgumentNullException(nameof(messageWindow));
|
||||
if (decoratedWriter == null)
|
||||
throw new ArgumentNullException(nameof(decoratedWriter));
|
||||
|
||||
_filter = filter;
|
||||
_messageWindow = messageWindow;
|
||||
_decoratedWriter = decoratedWriter;
|
||||
CreateTimer();
|
||||
_filter = filter ?? throw new ArgumentNullException(nameof(filter));
|
||||
_messageWindow = messageWindow ?? throw new ArgumentNullException(nameof(messageWindow));
|
||||
_decoratedWriter = decoratedWriter ?? throw new ArgumentNullException(nameof(decoratedWriter));
|
||||
}
|
||||
|
||||
public void Write(IMessage message)
|
||||
public async void Write(IMessage message)
|
||||
{
|
||||
if (WeShouldFocusNotificationPanel(message))
|
||||
BeginSwitchToPanel();
|
||||
_decoratedWriter.Write(message);
|
||||
|
||||
if (WeShouldFocusNotificationPanel(message))
|
||||
await SwitchToMessageAsync();
|
||||
}
|
||||
|
||||
private bool WeShouldFocusNotificationPanel(IMessage message)
|
||||
@@ -43,7 +36,8 @@ namespace mRemoteNG.Messages.WriterDecorators
|
||||
switch (message.Class)
|
||||
{
|
||||
case MessageClass.InformationMsg:
|
||||
if (_filter.AllowInfoMessages) return true;
|
||||
if (_filter.AllowInfoMessages)
|
||||
return true;
|
||||
break;
|
||||
case MessageClass.WarningMsg:
|
||||
if (_filter.AllowWarningMessages) return true;
|
||||
@@ -55,43 +49,46 @@ namespace mRemoteNG.Messages.WriterDecorators
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CreateTimer()
|
||||
private async Task SwitchToMessageAsync()
|
||||
{
|
||||
_ecTimer = new Timer
|
||||
{
|
||||
Enabled = false,
|
||||
Interval = 300
|
||||
};
|
||||
_ecTimer.Tick += SwitchTimerTick;
|
||||
}
|
||||
|
||||
private void BeginSwitchToPanel()
|
||||
{
|
||||
_ecTimer.Enabled = true;
|
||||
}
|
||||
|
||||
private void SwitchTimerTick(object sender, EventArgs e)
|
||||
{
|
||||
SwitchToMessage();
|
||||
_ecTimer.Enabled = false;
|
||||
await Task
|
||||
.Delay(TimeSpan.FromMilliseconds(300))
|
||||
.ContinueWith(task => SwitchToMessage());
|
||||
}
|
||||
|
||||
private void SwitchToMessage()
|
||||
{
|
||||
if (_messageWindow.InvokeRequired)
|
||||
{
|
||||
_frmMain.Invoke((MethodInvoker)SwitchToMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// do not attempt to focus the notification panel if it is in an inconsistent state
|
||||
if (_messageWindow.DockState == DockState.Unknown)
|
||||
return;
|
||||
|
||||
_messageWindow.PreviousActiveForm = (DockContent)_frmMain.pnlDock.ActiveContent;
|
||||
ShowMcForm();
|
||||
|
||||
// Show the notifications panel solution:
|
||||
// https://stackoverflow.com/questions/13843604/calling-up-dockpanel-suites-autohidden-dockcontent-programmatically
|
||||
if (AutoHideEnabled(_messageWindow))
|
||||
_frmMain.pnlDock.ActiveAutoHideContent = _messageWindow;
|
||||
else
|
||||
_messageWindow.Show(_frmMain.pnlDock);
|
||||
|
||||
_messageWindow.lvErrorCollector.Focus();
|
||||
_messageWindow.lvErrorCollector.SelectedItems.Clear();
|
||||
_messageWindow.lvErrorCollector.Items[0].Selected = true;
|
||||
_messageWindow.lvErrorCollector.FocusedItem = _messageWindow.lvErrorCollector.Items[0];
|
||||
}
|
||||
|
||||
private void ShowMcForm()
|
||||
private bool AutoHideEnabled(DockContent content)
|
||||
{
|
||||
if (_frmMain.pnlDock.InvokeRequired)
|
||||
_frmMain.pnlDock.Invoke((MethodInvoker)ShowMcForm);
|
||||
else
|
||||
_messageWindow.Show(_frmMain.pnlDock);
|
||||
return content.DockState == DockState.DockBottomAutoHide ||
|
||||
content.DockState == DockState.DockTopAutoHide ||
|
||||
content.DockState == DockState.DockLeftAutoHide ||
|
||||
content.DockState == DockState.DockRightAutoHide;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,5 +33,5 @@ using System.Runtime.InteropServices;
|
||||
// by using the '*' as shown below:
|
||||
// <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
[assembly: AssemblyVersion("1.76.4.*")]
|
||||
[assembly: AssemblyVersion("1.76.11.*")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
4
mRemoteV1/Properties/Settings.Designer.cs
generated
4
mRemoteV1/Properties/Settings.Designer.cs
generated
@@ -12,7 +12,7 @@ namespace mRemoteNG {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
@@ -2593,7 +2593,7 @@ namespace mRemoteNG {
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("General")]
|
||||
public string ConDefaultPanel {
|
||||
get {
|
||||
return ((string)(this["ConDefaultPanel"]));
|
||||
|
||||
@@ -645,7 +645,7 @@
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="ConDefaultPanel" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
<Value Profile="(Default)">General</Value>
|
||||
</Setting>
|
||||
<Setting Name="SaveConnectionsAfterEveryEdit" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
@@ -17,6 +17,10 @@
|
||||
-->
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
<applicationRequestMinimum>
|
||||
<PermissionSet Unrestricted="true" ID="Custom" SameSite="site" />
|
||||
<defaultAssemblyRequest permissionSetReference="Custom" />
|
||||
</applicationRequestMinimum>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</asmv1:assembly>
|
||||
</asmv1:assembly>
|
||||
63
mRemoteV1/Resources/Language/Language.Designer.cs
generated
63
mRemoteV1/Resources/Language/Language.Designer.cs
generated
@@ -60,6 +60,24 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to An error occurred while trying to reconnect to RDP host '{0}'.
|
||||
/// </summary>
|
||||
internal static string AutomaticReconnectError {
|
||||
get {
|
||||
return ResourceManager.GetString("AutomaticReconnectError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to An error occurred while trying to change the connection resolution to host '{0}'.
|
||||
/// </summary>
|
||||
internal static string ChangeConnectionResolutionError {
|
||||
get {
|
||||
return ResourceManager.GetString("ChangeConnectionResolutionError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Create a New Connection File.
|
||||
/// </summary>
|
||||
@@ -1711,6 +1729,15 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Delete....
|
||||
/// </summary>
|
||||
internal static string strDelete {
|
||||
get {
|
||||
return ResourceManager.GetString("strDelete", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Detect.
|
||||
/// </summary>
|
||||
@@ -2777,6 +2804,15 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Must Be Between 0 and 255.
|
||||
/// </summary>
|
||||
internal static string strIPRange {
|
||||
get {
|
||||
return ResourceManager.GetString("strIPRange", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to CTRL-ALT-DEL.
|
||||
/// </summary>
|
||||
@@ -4308,6 +4344,15 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Out Of Range.
|
||||
/// </summary>
|
||||
internal static string strOutOfRange {
|
||||
get {
|
||||
return ResourceManager.GetString("strOutOfRange", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Panel Name.
|
||||
/// </summary>
|
||||
@@ -6237,6 +6282,15 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reconnect All Connections.
|
||||
/// </summary>
|
||||
internal static string strReconnectAllConnections {
|
||||
get {
|
||||
return ResourceManager.GetString("strReconnectAllConnections", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reconnect to previously opened sessions on startup.
|
||||
/// </summary>
|
||||
@@ -7263,6 +7317,15 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to UltraVNC SingleClick.
|
||||
/// </summary>
|
||||
internal static string strUltraVNCSingleClick {
|
||||
get {
|
||||
return ResourceManager.GetString("strUltraVNCSingleClick", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Uncheck the properties you want not to be saved!.
|
||||
/// </summary>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
@@ -105,17 +105,17 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="strAbout" xml:space="preserve">
|
||||
<value>Acerca de</value>
|
||||
@@ -1224,7 +1224,7 @@ Ver el articulo de soporte de Microsoft en http://support.microsoft.com/kb/81183
|
||||
<value>Introduzca su dominio.</value>
|
||||
</data>
|
||||
<data name="strPropertyDescriptionEnableDesktopComposition" xml:space="preserve">
|
||||
<value>Seleccione si emplear composición de escrotorio o no.</value>
|
||||
<value>Seleccione si emplear composición de escritorio o no.</value>
|
||||
</data>
|
||||
<data name="strPropertyDescriptionEnableFontSmoothing" xml:space="preserve">
|
||||
<value>Seleccione si emplear suavizado de fuentes o no.</value>
|
||||
@@ -2069,4 +2069,4 @@ mRemoteNG ahora se cerrará y comenzará la instalación.</value>
|
||||
<data name="strYes" xml:space="preserve">
|
||||
<value>Sí</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
@@ -2679,4 +2679,25 @@ This page will walk you through the process of upgrading your connections file o
|
||||
<data name="strCreateEmptyPanelOnStartUp" xml:space="preserve">
|
||||
<value>Create an empty panel when mRemoteNG starts</value>
|
||||
</data>
|
||||
<data name="strIPRange" xml:space="preserve">
|
||||
<value>Must Be Between 0 and 255</value>
|
||||
</data>
|
||||
<data name="strOutOfRange" xml:space="preserve">
|
||||
<value>Out Of Range</value>
|
||||
</data>
|
||||
<data name="strDelete" xml:space="preserve">
|
||||
<value>Delete...</value>
|
||||
</data>
|
||||
<data name="strReconnectAllConnections" xml:space="preserve">
|
||||
<value>Reconnect All Connections</value>
|
||||
</data>
|
||||
<data name="strUltraVNCSingleClick" xml:space="preserve">
|
||||
<value>UltraVNC SingleClick</value>
|
||||
</data>
|
||||
<data name="AutomaticReconnectError" xml:space="preserve">
|
||||
<value>An error occurred while trying to reconnect to RDP host '{0}'</value>
|
||||
</data>
|
||||
<data name="ChangeConnectionResolutionError" xml:space="preserve">
|
||||
<value>An error occurred while trying to change the connection resolution to host '{0}'</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Security.Authentication
|
||||
{
|
||||
@@ -7,15 +9,16 @@ namespace mRemoteNG.Security.Authentication
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly string _cipherText;
|
||||
private readonly Func<Optional<SecureString>> _authenticationRequestor;
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public int MaxAttempts { get; set; } = 3;
|
||||
public SecureString LastAuthenticatedPassword { get; private set; }
|
||||
|
||||
public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, string cipherText)
|
||||
public PasswordAuthenticator(ICryptographyProvider cryptographyProvider, string cipherText, Func<Optional<SecureString>> authenticationRequestor)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider;
|
||||
_cipherText = cipherText;
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_cipherText = cipherText.ThrowIfNullOrEmpty(nameof(cipherText));
|
||||
_authenticationRequestor = authenticationRequestor.ThrowIfNull(nameof(authenticationRequestor));
|
||||
}
|
||||
|
||||
public bool Authenticate(SecureString password)
|
||||
@@ -32,7 +35,11 @@ namespace mRemoteNG.Security.Authentication
|
||||
}
|
||||
catch
|
||||
{
|
||||
password = AuthenticationRequestor?.Invoke();
|
||||
var providedPassword = _authenticationRequestor();
|
||||
if (!providedPassword.Any())
|
||||
return false;
|
||||
|
||||
password = providedPassword.First();
|
||||
if (password == null || password.Length == 0) break;
|
||||
}
|
||||
attempts++;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Security
|
||||
{
|
||||
public interface IKeyProvider
|
||||
{
|
||||
SecureString GetKey();
|
||||
Optional<SecureString> GetKey();
|
||||
}
|
||||
}
|
||||
@@ -9,35 +9,14 @@ namespace mRemoteNG.Themes
|
||||
/// </summary>
|
||||
public class PseudoKeyColor
|
||||
{
|
||||
private string key;
|
||||
private Color value;
|
||||
public PseudoKeyColor(string _key, Color _value)
|
||||
{
|
||||
key = _key;
|
||||
value = _value;
|
||||
}
|
||||
public string Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return key;
|
||||
}
|
||||
set
|
||||
{
|
||||
key = value;
|
||||
}
|
||||
}
|
||||
public Color Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return value;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
Key = _key;
|
||||
Value = _value;
|
||||
}
|
||||
public string Key { get; set; }
|
||||
|
||||
public Color Value { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -48,15 +27,14 @@ namespace mRemoteNG.Themes
|
||||
{
|
||||
#region Private Variables
|
||||
//Collection for color values that are not loaded by dock panels (list, buttons,panel content, etc)
|
||||
private Dictionary<string, Color> _extendedColors;
|
||||
private Dictionary<string, Color> _default;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public ExtendedColorPalette()
|
||||
{
|
||||
_extendedColors = new Dictionary<string, Color>();
|
||||
_default = new Dictionary<string, Color>(); // If this is the default palette, it will not have a default-default palette
|
||||
ExtColorPalette = new Dictionary<string, Color>();
|
||||
DefaultColorPalette = new Dictionary<string, Color>(); // If this is the default palette, it will not have a default-default palette
|
||||
|
||||
}
|
||||
#endregion
|
||||
@@ -65,7 +43,7 @@ namespace mRemoteNG.Themes
|
||||
// Set the default theme, that theme should contain all color values used by the application
|
||||
public void setDefault(ExtendedColorPalette inPalettte)
|
||||
{
|
||||
_default = inPalettte._extendedColors;
|
||||
DefaultColorPalette = inPalettte.ExtColorPalette;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -76,12 +54,12 @@ namespace mRemoteNG.Themes
|
||||
/// <returns></returns>
|
||||
public Color getColor(string colorKey)
|
||||
{
|
||||
var retColor = _extendedColors.ContainsKey(colorKey) ? _extendedColors[colorKey]:Color.Empty;
|
||||
var retColor = ExtColorPalette.ContainsKey(colorKey) ? ExtColorPalette[colorKey]:Color.Empty;
|
||||
//Invisible colors are not good, might indicate missing color from the palette as is represented by 00000000
|
||||
if (retColor != Color.Empty && retColor.A != 0) return retColor;
|
||||
if(_default != null)
|
||||
if(DefaultColorPalette != null)
|
||||
{
|
||||
retColor = _default.ContainsKey(colorKey) ? _default[colorKey] : Color.Empty;
|
||||
retColor = DefaultColorPalette.ContainsKey(colorKey) ? DefaultColorPalette[colorKey] : Color.Empty;
|
||||
}
|
||||
//why are we here?, just avoid a crash
|
||||
if(retColor == Color.Empty)
|
||||
@@ -100,7 +78,7 @@ namespace mRemoteNG.Themes
|
||||
/// <param name="inColor"></param>
|
||||
public void addColor(string colorKey,Color inColor)
|
||||
{
|
||||
_extendedColors.Add(colorKey, inColor);
|
||||
ExtColorPalette.Add(colorKey, inColor);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,33 +89,13 @@ namespace mRemoteNG.Themes
|
||||
/// <param name="inColor"></param>
|
||||
public void replaceColor(string colorKey, Color inColor)
|
||||
{
|
||||
_extendedColors[colorKey]= inColor;
|
||||
ExtColorPalette[colorKey]= inColor;
|
||||
}
|
||||
|
||||
public Dictionary<string, Color> DefaultColorPalette
|
||||
{
|
||||
get
|
||||
{
|
||||
return _default;
|
||||
}
|
||||
set
|
||||
{
|
||||
_default = value;
|
||||
}
|
||||
}
|
||||
public Dictionary<string, Color> DefaultColorPalette { get; set; }
|
||||
|
||||
|
||||
public Dictionary<string, Color> ExtColorPalette
|
||||
{
|
||||
get
|
||||
{
|
||||
return _extendedColors;
|
||||
}
|
||||
set
|
||||
{
|
||||
_extendedColors = value;
|
||||
}
|
||||
}
|
||||
public Dictionary<string, Color> ExtColorPalette { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace mRemoteNG.Themes
|
||||
foreach (DictionaryEntry entry in resourceSet)
|
||||
{
|
||||
var colorName = entry.Key.ToString();
|
||||
var xmlQueryPath = (string)entry.Value;
|
||||
var xmlQueryPath = entry.Value.ToString();
|
||||
if (_xml.DocumentElement == null) continue;
|
||||
var colorNodeList = _xml.DocumentElement.FirstChild.SelectNodes(xmlQueryPath);
|
||||
var color = colorNodeList != null && colorNodeList.Count > 0 ? colorNodeList[0].Value : null;
|
||||
@@ -60,7 +60,7 @@ namespace mRemoteNG.Themes
|
||||
foreach (DictionaryEntry entry in resourceSet)
|
||||
{
|
||||
var colorName = entry.Key.ToString();
|
||||
var xmlQueryPath = (string)entry.Value;
|
||||
var xmlQueryPath = entry.Value.ToString();
|
||||
var colorNodeList = _xml.DocumentElement?.FirstChild.SelectNodes(xmlQueryPath);
|
||||
if (colorNodeList == null || colorNodeList.Count <= 0) continue;
|
||||
var paletteColor = colorPalette.getColor(colorName);
|
||||
|
||||
@@ -7,6 +7,7 @@ using WeifenLuo.WinFormsUI.Docking;
|
||||
namespace mRemoteNG.Themes
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Container class for all the color and style elements to define a theme
|
||||
/// </summary>
|
||||
@@ -15,34 +16,32 @@ namespace mRemoteNG.Themes
|
||||
#region Private Variables
|
||||
private string _name;
|
||||
private ThemeBase _theme;
|
||||
private String _URI;
|
||||
private string _URI;
|
||||
private VisualStudioToolStripExtender.VsVersion _version;
|
||||
private ExtendedColorPalette _extendedPalette;
|
||||
private bool _isThemeBase;
|
||||
private bool _isExtendable;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public ThemeInfo(string themeName, ThemeBase inTheme, String inURI, VisualStudioToolStripExtender.VsVersion inVersion, ExtendedColorPalette inExtendedPalette)
|
||||
public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion, ExtendedColorPalette inExtendedPalette)
|
||||
{
|
||||
_name = themeName;
|
||||
_theme = inTheme;
|
||||
_URI = inURI;
|
||||
_version = inVersion;
|
||||
_extendedPalette = inExtendedPalette;
|
||||
_isThemeBase = false;
|
||||
_isExtendable = false;
|
||||
IsThemeBase = false;
|
||||
IsExtendable = false;
|
||||
}
|
||||
|
||||
public ThemeInfo(string themeName, ThemeBase inTheme, String inURI, VisualStudioToolStripExtender.VsVersion inVersion)
|
||||
public ThemeInfo(string themeName, ThemeBase inTheme, string inURI, VisualStudioToolStripExtender.VsVersion inVersion)
|
||||
{
|
||||
_name = themeName;
|
||||
_theme = inTheme;
|
||||
_URI = inURI;
|
||||
_version = inVersion;
|
||||
_isThemeBase = false;
|
||||
_isExtendable = false;
|
||||
IsThemeBase = false;
|
||||
IsExtendable = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -57,8 +56,8 @@ namespace mRemoteNG.Themes
|
||||
};
|
||||
var clonedObj = new ThemeInfo(_name, _theme, _URI, _version, extPalette)
|
||||
{
|
||||
IsExtendable = _isExtendable,
|
||||
IsThemeBase = _isThemeBase
|
||||
IsExtendable = IsExtendable,
|
||||
IsThemeBase = IsThemeBase
|
||||
};
|
||||
|
||||
return clonedObj;
|
||||
@@ -71,8 +70,8 @@ namespace mRemoteNG.Themes
|
||||
[Browsable(false)]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (string.Equals(_name, value, StringComparison.InvariantCulture))
|
||||
{
|
||||
@@ -84,7 +83,7 @@ namespace mRemoteNG.Themes
|
||||
|
||||
public ThemeBase Theme
|
||||
{
|
||||
get { return _theme; }
|
||||
get => _theme;
|
||||
set
|
||||
{
|
||||
if (value != null && _theme == value)
|
||||
@@ -97,7 +96,7 @@ namespace mRemoteNG.Themes
|
||||
|
||||
public string URI
|
||||
{
|
||||
get { return _URI; }
|
||||
get => _URI;
|
||||
set
|
||||
{
|
||||
if (value != null && _URI == value)
|
||||
@@ -110,7 +109,7 @@ namespace mRemoteNG.Themes
|
||||
|
||||
public VisualStudioToolStripExtender.VsVersion Version
|
||||
{
|
||||
get { return _version; }
|
||||
get => _version;
|
||||
set
|
||||
{
|
||||
if (Equals(_version, value))
|
||||
@@ -123,7 +122,7 @@ namespace mRemoteNG.Themes
|
||||
|
||||
public ExtendedColorPalette ExtendedPalette
|
||||
{
|
||||
get { return _extendedPalette; }
|
||||
get => _extendedPalette;
|
||||
set
|
||||
{
|
||||
if (_extendedPalette != null && _extendedPalette == value)
|
||||
@@ -134,23 +133,10 @@ namespace mRemoteNG.Themes
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsThemeBase
|
||||
{
|
||||
get { return _isThemeBase; }
|
||||
set
|
||||
{
|
||||
_isThemeBase = value;
|
||||
}
|
||||
}
|
||||
public bool IsThemeBase { get; set; }
|
||||
|
||||
public bool IsExtendable { get; set; }
|
||||
|
||||
public bool IsExtendable
|
||||
{
|
||||
get { return _isExtendable; }
|
||||
set
|
||||
{
|
||||
_isExtendable = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -46,11 +46,7 @@ namespace mRemoteNG.Themes
|
||||
#region Public Methods
|
||||
public static ThemeManager getInstance()
|
||||
{
|
||||
if(themeInstance == null)
|
||||
{
|
||||
themeInstance = new ThemeManager();
|
||||
}
|
||||
return themeInstance;
|
||||
return themeInstance ?? (themeInstance = new ThemeManager());
|
||||
}
|
||||
|
||||
|
||||
@@ -64,80 +60,74 @@ namespace mRemoteNG.Themes
|
||||
//THe manager precharges all the themes at once
|
||||
public List<ThemeInfo> LoadThemes()
|
||||
{
|
||||
if (themes == null)
|
||||
if (themes != null) return themes.Values.OfType<ThemeInfo>().ToList();
|
||||
themes = new Hashtable();
|
||||
|
||||
//Load the files in theme folder first, to incluide vstheme light as default
|
||||
var themePath = App.Info.SettingsFileInfo.ThemeFolder;
|
||||
if (themePath == null) return themes.Values.OfType<ThemeInfo>().ToList();
|
||||
try
|
||||
{
|
||||
themes = new Hashtable();
|
||||
|
||||
//Load the files in theme folder first, to incluide vstheme light as default
|
||||
string themePath = App.Info.SettingsFileInfo.ThemeFolder;
|
||||
if (themePath != null)
|
||||
//In install mode first time is necesary to copy the themes folder
|
||||
if (!Directory.Exists(themePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
//In install mode first time is necesary to copy the themes folder
|
||||
if (!Directory.Exists(themePath))
|
||||
{
|
||||
Directory.CreateDirectory(themePath);
|
||||
Directory.CreateDirectory(themePath);
|
||||
|
||||
}
|
||||
DirectoryInfo orig = new DirectoryInfo(App.Info.SettingsFileInfo.InstalledThemeFolder);
|
||||
FileInfo[] files = orig.GetFiles();
|
||||
foreach (FileInfo file in files)
|
||||
{
|
||||
}
|
||||
var orig = new DirectoryInfo(App.Info.SettingsFileInfo.InstalledThemeFolder);
|
||||
var files = orig.GetFiles();
|
||||
foreach (var file in files)
|
||||
{
|
||||
|
||||
if (!File.Exists(Path.Combine(themePath, file.Name)))
|
||||
file.CopyTo(Path.Combine(themePath, file.Name), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Check that theme folder exist before trying to load themes
|
||||
if (Directory.Exists(themePath))
|
||||
{
|
||||
string[] themeFiles = Directory.GetFiles(themePath, "*.vstheme");
|
||||
string defaultThemeURL = Directory.GetFiles(themePath, "vs2015light" + ".vstheme")[0];
|
||||
//First we load the default theme, its vs2015light
|
||||
ThemeInfo defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL);
|
||||
themes.Add(defaultTheme.Name, defaultTheme);
|
||||
//Then the rest
|
||||
foreach (string themeFile in themeFiles)
|
||||
{
|
||||
//filter default one
|
||||
ThemeInfo extTheme = ThemeSerializer.LoadFromXmlFile(themeFile, defaultTheme);
|
||||
if (extTheme.Theme != null && !themes.ContainsKey(extTheme.Name))
|
||||
{
|
||||
themes.Add(extTheme.Name, extTheme);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme
|
||||
ThemeInfo vs2003 = new ThemeInfo("Vs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2003.Name, vs2003);
|
||||
ThemeInfo vs2005 = new ThemeInfo("Vs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2005.Name, vs2005);
|
||||
ThemeInfo vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2012Light.Name, vs2012Light);
|
||||
ThemeInfo vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette);
|
||||
themes.Add(vs2012Dark.Name, vs2012Dark);
|
||||
ThemeInfo vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette);
|
||||
themes.Add(vs2012Blue.Name, vs2012Blue);
|
||||
ThemeInfo vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2013Light.Name, vs2013Light);
|
||||
ThemeInfo vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette);
|
||||
themes.Add(vs2013Dark.Name, vs2013Dark);
|
||||
ThemeInfo vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette);
|
||||
themes.Add(vs2013Blue.Name, vs2013Blue);
|
||||
}
|
||||
}
|
||||
catch(Exception ex )
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Error loading themes" + Environment.NewLine + ex.Message, true);
|
||||
}
|
||||
|
||||
if (!File.Exists(Path.Combine(themePath, file.Name)))
|
||||
file.CopyTo(Path.Combine(themePath, file.Name), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Check that theme folder exist before trying to load themes
|
||||
if (Directory.Exists(themePath))
|
||||
{
|
||||
var themeFiles = Directory.GetFiles(themePath, "*.vstheme");
|
||||
var defaultThemeURL = Directory.GetFiles(themePath, "vs2015light" + ".vstheme")[0];
|
||||
//First we load the default theme, its vs2015light
|
||||
var defaultTheme = ThemeSerializer.LoadFromXmlFile(defaultThemeURL);
|
||||
themes.Add(defaultTheme.Name, defaultTheme);
|
||||
//Then the rest
|
||||
foreach (var themeFile in themeFiles)
|
||||
{
|
||||
//filter default one
|
||||
var extTheme = ThemeSerializer.LoadFromXmlFile(themeFile, defaultTheme);
|
||||
if (extTheme.Theme != null && !themes.ContainsKey(extTheme.Name))
|
||||
{
|
||||
themes.Add(extTheme.Name, extTheme);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Load the embedded themes, extended palettes are taken from the vs2015 themes, trying to match the color theme
|
||||
var vs2003 = new ThemeInfo("Vs2003", new VS2003Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2003, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2003.Name, vs2003);
|
||||
var vs2005 = new ThemeInfo("Vs2005", new VS2005Theme(), "", VisualStudioToolStripExtender.VsVersion.Vs2005, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2005.Name, vs2005);
|
||||
var vs2012Light = new ThemeInfo("vs2012Light", new VS2012LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2012Light.Name, vs2012Light);
|
||||
var vs2012Dark = new ThemeInfo("vs2012Dark", new VS2012DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette);
|
||||
themes.Add(vs2012Dark.Name, vs2012Dark);
|
||||
var vs2012Blue = new ThemeInfo("vs2012Blue", new VS2012BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2012, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette);
|
||||
themes.Add(vs2012Blue.Name, vs2012Blue);
|
||||
var vs2013Light = new ThemeInfo("vs2013Light", new VS2013LightTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015light"]).ExtendedPalette);
|
||||
themes.Add(vs2013Light.Name, vs2013Light);
|
||||
var vs2013Dark = new ThemeInfo("vs2013Dark", new VS2013DarkTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015dark"]).ExtendedPalette);
|
||||
themes.Add(vs2013Dark.Name, vs2013Dark);
|
||||
var vs2013Blue = new ThemeInfo("vs2013Blue", new VS2013BlueTheme(), "", VisualStudioToolStripExtender.VsVersion.Vs2013, ((ThemeInfo)themes["vs2015blue"]).ExtendedPalette);
|
||||
themes.Add(vs2013Blue.Name, vs2013Blue);
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Error loading themes" + Environment.NewLine + ex.Message, true);
|
||||
}
|
||||
return themes.Values.OfType<ThemeInfo>().ToList();
|
||||
}
|
||||
|
||||
@@ -149,29 +139,24 @@ namespace mRemoteNG.Themes
|
||||
/// <returns></returns>
|
||||
public ThemeInfo addTheme(ThemeInfo baseTheme, string newThemeName)
|
||||
{
|
||||
if (!themes.Contains(newThemeName))
|
||||
{
|
||||
ThemeInfo modifiedTheme = (ThemeInfo)baseTheme.Clone();
|
||||
modifiedTheme.Name = newThemeName;
|
||||
modifiedTheme.IsExtendable = true;
|
||||
modifiedTheme.IsThemeBase = false;
|
||||
ThemeSerializer.SaveToXmlFile(modifiedTheme,baseTheme);
|
||||
themes.Add(newThemeName,modifiedTheme);
|
||||
return modifiedTheme;
|
||||
}
|
||||
return null;
|
||||
if (themes.Contains(newThemeName)) return null;
|
||||
var modifiedTheme = (ThemeInfo)baseTheme.Clone();
|
||||
modifiedTheme.Name = newThemeName;
|
||||
modifiedTheme.IsExtendable = true;
|
||||
modifiedTheme.IsThemeBase = false;
|
||||
ThemeSerializer.SaveToXmlFile(modifiedTheme,baseTheme);
|
||||
themes.Add(newThemeName,modifiedTheme);
|
||||
return modifiedTheme;
|
||||
}
|
||||
|
||||
//Delete a theme from memory and disk
|
||||
public void deleteTheme(ThemeInfo themeToDelete)
|
||||
{
|
||||
if (themes.Contains(themeToDelete.Name))
|
||||
{
|
||||
if(ActiveTheme == themeToDelete)
|
||||
ActiveTheme = DefaultTheme;
|
||||
themes.Remove(themeToDelete.Name);
|
||||
ThemeSerializer.DeleteFile(themeToDelete);
|
||||
}
|
||||
if (!themes.Contains(themeToDelete.Name)) return;
|
||||
if(ActiveTheme == themeToDelete)
|
||||
ActiveTheme = DefaultTheme;
|
||||
themes.Remove(themeToDelete.Name);
|
||||
ThemeSerializer.DeleteFile(themeToDelete);
|
||||
}
|
||||
|
||||
//Sincronize the theme XML values from memory to disk
|
||||
@@ -191,10 +176,8 @@ namespace mRemoteNG.Themes
|
||||
{
|
||||
if (themes.Contains(name))
|
||||
return false;
|
||||
char[] badChars = Path.GetInvalidFileNameChars();
|
||||
if (name.IndexOfAny(badChars) != -1)
|
||||
return false;
|
||||
return true;
|
||||
var badChars = Path.GetInvalidFileNameChars();
|
||||
return name.IndexOfAny(badChars) == -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,10 +189,11 @@ namespace mRemoteNG.Themes
|
||||
|
||||
public event ThemeChangedEventHandler ThemeChanged
|
||||
{
|
||||
add { ThemeChangedEvent = (ThemeChangedEventHandler)System.Delegate.Combine(ThemeChangedEvent, value); }
|
||||
remove { ThemeChangedEvent = (ThemeChangedEventHandler)System.Delegate.Remove(ThemeChangedEvent, value); }
|
||||
add => ThemeChangedEvent = (ThemeChangedEventHandler)Delegate.Combine(ThemeChangedEvent, value);
|
||||
remove => ThemeChangedEvent = (ThemeChangedEventHandler)Delegate.Remove(ThemeChangedEvent, value);
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedParameter.Local
|
||||
private void NotifyThemeChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == "Name")
|
||||
@@ -223,44 +207,29 @@ namespace mRemoteNG.Themes
|
||||
#region Properties
|
||||
public bool ThemingActive
|
||||
{
|
||||
get
|
||||
{
|
||||
return _themeActive;
|
||||
}
|
||||
get => _themeActive;
|
||||
set
|
||||
{
|
||||
if(themes.Count != 0)
|
||||
{
|
||||
_themeActive = value;
|
||||
Settings.Default.ThemingActive = value;
|
||||
NotifyThemeChanged(this, new PropertyChangedEventArgs(""));
|
||||
}
|
||||
if (themes.Count == 0) return;
|
||||
_themeActive = value;
|
||||
Settings.Default.ThemingActive = value;
|
||||
NotifyThemeChanged(this, new PropertyChangedEventArgs(""));
|
||||
}
|
||||
}
|
||||
|
||||
private ThemeInfo DefaultTheme
|
||||
{
|
||||
get
|
||||
{
|
||||
return (ThemeInfo) themes["vs2015light"];
|
||||
}
|
||||
}
|
||||
|
||||
public ThemeInfo DefaultTheme => (ThemeInfo) themes["vs2015light"];
|
||||
|
||||
public ThemeInfo ActiveTheme
|
||||
{
|
||||
get
|
||||
{
|
||||
return _activeTheme;
|
||||
}
|
||||
set
|
||||
// default if themes are not enabled
|
||||
get => ThemingActive == false ? DefaultTheme : _activeTheme;
|
||||
set
|
||||
{
|
||||
//You can only enable theming if there are themes laoded
|
||||
if(value != null)
|
||||
{
|
||||
_activeTheme = value;
|
||||
Settings.Default.ThemeName = value.Name;
|
||||
NotifyThemeChanged(this, new PropertyChangedEventArgs("theme"));
|
||||
}
|
||||
if (value == null) return;
|
||||
_activeTheme = value;
|
||||
Settings.Default.ThemeName = value.Name;
|
||||
NotifyThemeChanged(this, new PropertyChangedEventArgs("theme"));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -1,25 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
using System.Linq;
|
||||
|
||||
namespace mRemoteNG.Themes
|
||||
{
|
||||
public class ThemeSerializer
|
||||
public static class ThemeSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Save the theme to file, name property is used as filename
|
||||
/// The baseTheme is used as a template, by copy that file and rewrite the extpalette values
|
||||
/// </summary>
|
||||
/// <param name="themeInfo"></param>
|
||||
public static void SaveToXmlFile(ThemeInfo themeToSave,ThemeInfo baseTheme)
|
||||
/// <summary>
|
||||
/// Save the theme to file, name property is used as filename
|
||||
/// The baseTheme is used as a template, by copy that file and rewrite the extpalette values
|
||||
/// </summary>
|
||||
/// <param name="themeToSave"></param>
|
||||
/// <param name="baseTheme"></param>
|
||||
public static void SaveToXmlFile(ThemeInfo themeToSave,ThemeInfo baseTheme)
|
||||
{
|
||||
string oldURI = baseTheme.URI;
|
||||
String directoryName = Path.GetDirectoryName(oldURI);
|
||||
string toSaveURI = directoryName + Path.DirectorySeparatorChar + themeToSave.Name + ".vstheme";
|
||||
var oldURI = baseTheme.URI;
|
||||
var directoryName = Path.GetDirectoryName(oldURI);
|
||||
var toSaveURI = directoryName + Path.DirectorySeparatorChar + themeToSave.Name + ".vstheme";
|
||||
File.Copy(baseTheme.URI, toSaveURI);
|
||||
themeToSave.URI = toSaveURI;
|
||||
}
|
||||
@@ -35,10 +32,9 @@ namespace mRemoteNG.Themes
|
||||
/// <param name="themeToUpdate"></param>
|
||||
public static void UpdateThemeXMLValues(ThemeInfo themeToUpdate)
|
||||
{
|
||||
byte[] bytesIn = File.ReadAllBytes(themeToUpdate.URI);
|
||||
MremoteNGPaletteManipulator manipulator;
|
||||
manipulator = new MremoteNGPaletteManipulator(bytesIn, themeToUpdate.ExtendedPalette);
|
||||
byte[] bytesOut = manipulator.mergePalette(themeToUpdate.ExtendedPalette);
|
||||
var bytesIn = File.ReadAllBytes(themeToUpdate.URI);
|
||||
var manipulator = new MremoteNGPaletteManipulator(bytesIn, themeToUpdate.ExtendedPalette);
|
||||
var bytesOut = manipulator.mergePalette(themeToUpdate.ExtendedPalette);
|
||||
File.WriteAllBytes(themeToUpdate.URI, bytesOut);
|
||||
}
|
||||
|
||||
@@ -50,22 +46,22 @@ namespace mRemoteNG.Themes
|
||||
/// <returns></returns>
|
||||
public static ThemeInfo LoadFromXmlFile(string filename, ThemeInfo defaultTheme=null)
|
||||
{
|
||||
byte[] bytes = File.ReadAllBytes(filename);
|
||||
var bytes = File.ReadAllBytes(filename);
|
||||
//Load the dockpanel part
|
||||
MremoteNGThemeBase themeBaseLoad= new MremoteNGThemeBase(bytes);
|
||||
var themeBaseLoad= new MremoteNGThemeBase(bytes);
|
||||
//Load the mremote part
|
||||
MremoteNGPaletteManipulator extColorLoader;
|
||||
//Cause we cannot default the theme for the default theme
|
||||
extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme ==null ? null:defaultTheme.ExtendedPalette);
|
||||
ThemeInfo loadedTheme = new ThemeInfo(Path.GetFileNameWithoutExtension(filename), themeBaseLoad, filename, VisualStudioToolStripExtender.VsVersion.Vs2015, extColorLoader.getColors());
|
||||
if((new string[] { "darcula", "vs2015blue", "vs2015dark" , "vs2015light" }).Contains(Path.GetFileNameWithoutExtension(filename)))
|
||||
//Cause we cannot default the theme for the default theme
|
||||
var extColorLoader = new MremoteNGPaletteManipulator(bytes, defaultTheme?.ExtendedPalette);
|
||||
var loadedTheme = new ThemeInfo(Path.GetFileNameWithoutExtension(filename), themeBaseLoad, filename, VisualStudioToolStripExtender.VsVersion.Vs2015, extColorLoader.getColors());
|
||||
if(new[] { "darcula", "vs2015blue", "vs2015dark" , "vs2015light" }.Contains(Path.GetFileNameWithoutExtension(filename)))
|
||||
{
|
||||
loadedTheme.IsThemeBase = true;
|
||||
}
|
||||
loadedTheme.IsExtendable = true;
|
||||
return loadedTheme;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
private static string EncodeColorName(Color color)
|
||||
{
|
||||
// best/simplest answer to converting to hex: http://stackoverflow.com/questions/12078942/how-to-convert-from-argb-to-hex-aarrggbb
|
||||
@@ -77,7 +73,7 @@ namespace mRemoteNG.Themes
|
||||
var regex = new System.Text.RegularExpressions.Regex("^[0-9a-fA-F]{8}$");
|
||||
return regex.Match(name).Success ? Color.FromArgb(Convert.ToInt32(name, 16)) : Color.FromName(name);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.AccessControl;
|
||||
using Microsoft.Win32;
|
||||
using mRemoteNG.App;
|
||||
@@ -38,14 +39,16 @@ namespace mRemoteNG.Tools
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(string.Concat("Software\\Wow6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
key?.DeleteValue(appName);
|
||||
if (key?.GetValueNames().Contains(appName) ?? false)
|
||||
key.DeleteValue(appName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using (var key = Registry.CurrentUser.CreateSubKey(string.Concat("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\", feature), RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
key?.DeleteValue(appName);
|
||||
if (key?.GetValueNames().Contains(appName) ?? false)
|
||||
key.DeleteValue(appName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@ using static System.String;
|
||||
|
||||
namespace mRemoteNG.Tools
|
||||
{
|
||||
public static class MiscTools
|
||||
public static class MiscTools
|
||||
{
|
||||
public static Icon GetIconFromFile(string FileName)
|
||||
{
|
||||
@@ -34,7 +34,7 @@ namespace mRemoteNG.Tools
|
||||
}
|
||||
}
|
||||
|
||||
public static SecureString PasswordDialog(string passwordName = null, bool verify = true)
|
||||
public static Optional<SecureString> PasswordDialog(string passwordName = null, bool verify = true)
|
||||
{
|
||||
var passwordForm = new PasswordForm(passwordName, verify);
|
||||
return passwordForm.GetKey();
|
||||
|
||||
@@ -1,50 +1,152 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace mRemoteNG.Tools
|
||||
{
|
||||
public class Optional<T> : IEnumerable<T>
|
||||
{
|
||||
private readonly T[] _maybe;
|
||||
/// <summary>
|
||||
/// Represents a type that may or may not have been assigned a value.
|
||||
/// A strongly typed collection that contains either 0 or 1 values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The underlying type that may or may not have a value</typeparam>
|
||||
public class Optional<T> : IEnumerable<T>, IComparable<Optional<T>>
|
||||
{
|
||||
private readonly T[] _optional;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new empty instance of Optional
|
||||
/// </summary>
|
||||
public Optional()
|
||||
{
|
||||
_maybe = new T[0];
|
||||
_optional = new T[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance of Optional from the given value.
|
||||
/// If the value is null, the Optional will be empty
|
||||
/// </summary>
|
||||
public Optional(T value)
|
||||
{
|
||||
_maybe = value != null
|
||||
_optional = value != null
|
||||
? new[] {value}
|
||||
: new T[0];
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
public override string ToString()
|
||||
{
|
||||
return _optional.Any() ? _optional.First().ToString() : "";
|
||||
}
|
||||
|
||||
public static implicit operator Optional<T>(T value)
|
||||
{
|
||||
return new Optional<T>(value);
|
||||
}
|
||||
|
||||
public static Optional<TOut> FromNullable<TOut>(TOut? value) where TOut : struct
|
||||
{
|
||||
return value.HasValue
|
||||
? new Optional<TOut>(value.Value)
|
||||
: new Optional<TOut>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an empty <see cref="Optional{T}"/>
|
||||
/// </summary>
|
||||
public static Optional<T> Empty => new Optional<T>();
|
||||
|
||||
#region IEnumerable
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<T>)_maybe).GetEnumerator();
|
||||
return ((IEnumerable<T>)_optional).GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override string ToString()
|
||||
#region IComparable
|
||||
/// <summary>
|
||||
/// Compares this <see cref="Optional{T}"/> to another instance
|
||||
/// of the same type. For purposes of comparison, empty Optional
|
||||
/// objects are treated like Null and will be valued lower than
|
||||
/// an Optional that contains a value. If both Optionals contain
|
||||
/// values, the values are compared directly.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
public int CompareTo(Optional<T> other)
|
||||
{
|
||||
var otherHasAnything = other.Any();
|
||||
var thisHasAnything = _optional.Length > 0;
|
||||
|
||||
// both are empty, equivalent value
|
||||
if (!thisHasAnything && !otherHasAnything)
|
||||
return 0;
|
||||
// we are empty, they are greater value
|
||||
if (!thisHasAnything)
|
||||
return -1;
|
||||
// they are empty, we are greater value
|
||||
if (!otherHasAnything)
|
||||
return 1;
|
||||
// neither are empty, compare wrapped objects directly
|
||||
if (_optional[0] is IComparable<T>)
|
||||
return ((IComparable<T>)_optional[0]).CompareTo(other.First());
|
||||
|
||||
throw new ArgumentException(string.Format(
|
||||
"Cannot compare objects. Optional type {0} is not comparable to itself",
|
||||
typeof(T).FullName));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Override Equals and GetHashCode
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return _maybe.Any() ? _maybe.First().ToString() : "";
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
|
||||
var objAsOptional = obj as Optional<T>;
|
||||
if (objAsOptional != null)
|
||||
return Equals(objAsOptional);
|
||||
|
||||
if (obj is T)
|
||||
Equals((T)obj);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static implicit operator Optional<T>(T value)
|
||||
public bool Equals(Optional<T> other)
|
||||
{
|
||||
return new Optional<T>(value);
|
||||
var otherObj = other.FirstOrDefault();
|
||||
var thisObj = _optional.FirstOrDefault();
|
||||
if (thisObj == null && otherObj == null)
|
||||
return true;
|
||||
if (thisObj == null)
|
||||
return false;
|
||||
return thisObj.Equals(otherObj);
|
||||
}
|
||||
|
||||
public static Optional<TOut> FromNullable<TOut>(TOut? value) where TOut : struct
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return value.HasValue
|
||||
? new Optional<TOut>(value.Value)
|
||||
: new Optional<TOut>();
|
||||
return _optional != null
|
||||
? _optional.GetHashCode()
|
||||
: 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
public static bool operator ==(Optional<T> left, Optional<T> right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Optional<T> left, Optional<T> right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Tree
|
||||
{
|
||||
public sealed class ConnectionTreeModel : INotifyCollectionChanged, INotifyPropertyChanged
|
||||
public sealed class ConnectionTreeModel : INotifyCollectionChanged, INotifyPropertyChanged
|
||||
{
|
||||
public List<ContainerInfo> RootNodes { get; } = new List<ContainerInfo>();
|
||||
|
||||
|
||||
@@ -66,7 +66,9 @@ namespace mRemoteNG.Tree.Root
|
||||
|
||||
public override TreeNodeType GetTreeNodeType()
|
||||
{
|
||||
return TreeNodeType.Root;
|
||||
return Type == RootNodeType.Connection
|
||||
? TreeNodeType.Root
|
||||
: TreeNodeType.PuttyRoot;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace mRemoteNG.Tree
|
||||
|
||||
public bool Confirm(ConnectionInfo deletionTarget)
|
||||
{
|
||||
if (deletionTarget == null)
|
||||
return false;
|
||||
|
||||
var deletionTargetAsContainer = deletionTarget as ContainerInfo;
|
||||
if (deletionTargetAsContainer != null)
|
||||
return deletionTargetAsContainer.HasChildren()
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace mRemoteNG.UI.Controls.Base
|
||||
else
|
||||
e.Graphics.FillRectangle(new SolidBrush(_themeManager.ActiveTheme.ExtendedPalette.getColor("ComboBox_Background")), e.Bounds);
|
||||
|
||||
if(DisplayMember == null || DisplayMember == "")
|
||||
if(string.IsNullOrEmpty(DisplayMember))
|
||||
e.Graphics.DrawString(Items[index].ToString(), e.Font, itemBrush, e.Bounds, StringFormat.GenericDefault);
|
||||
else
|
||||
{
|
||||
@@ -129,7 +129,7 @@ namespace mRemoteNG.UI.Controls.Base
|
||||
}
|
||||
|
||||
//Arrow
|
||||
e.Graphics.DrawString("\u25BC", this.Font, new SolidBrush(ButtFore), Width-17, Height/2 -5);
|
||||
e.Graphics.DrawString("\u25BC", Font, new SolidBrush(ButtFore), Width-17, Height/2 -5);
|
||||
|
||||
//Text
|
||||
var textRect = new Rectangle(2, 2, Width - 20, Height - 4);
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace mRemoteNG.UI.Controls.Base
|
||||
{
|
||||
private ThemeManager _themeManager;
|
||||
|
||||
public NGGroupBox() : base()
|
||||
public NGGroupBox()
|
||||
{
|
||||
ThemeManager.getInstance().ThemeChanged += OnCreateControl;
|
||||
}
|
||||
|
||||
@@ -23,10 +23,12 @@ namespace mRemoteNG.UI.Controls.Base
|
||||
{
|
||||
base.OnCreateControl();
|
||||
_themeManager = ThemeManager.getInstance();
|
||||
if (_themeManager.ThemingActive)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
if (!_themeManager.ThemingActive) return;
|
||||
// Use the Dialog_* colors since Labels generally have the same colors as panels/dialogs/windows/etc...
|
||||
BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Background");
|
||||
ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground");
|
||||
FontOverrider.FontOverride(this);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,16 +40,17 @@ namespace mRemoteNG.UI.Controls.Base
|
||||
return;
|
||||
}
|
||||
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
|
||||
// let's use the defaults - this looks terrible in my testing....
|
||||
//e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
//e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
|
||||
if (Enabled)
|
||||
{
|
||||
TextRenderer.DrawText(e.Graphics, this.Text, Font, ClientRectangle, ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
|
||||
TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
var disabledtextLabel = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Disabled_Foreground");
|
||||
TextRenderer.DrawText(e.Graphics, this.Text, Font, ClientRectangle, disabledtextLabel, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
|
||||
TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, disabledtextLabel, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using mRemoteNG.Themes;
|
||||
using System;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Themes;
|
||||
// ReSharper disable LocalizableElement
|
||||
|
||||
namespace mRemoteNG.UI.Controls.Base
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace mRemoteNG.UI.Controls.Base
|
||||
private NGButton Up;
|
||||
private NGButton Down;
|
||||
|
||||
public NGNumericUpDown() : base()
|
||||
public NGNumericUpDown()
|
||||
{
|
||||
_themeManager = ThemeManager.getInstance();
|
||||
ThemeManager.getInstance().ThemeChanged += OnCreateControl;
|
||||
@@ -28,7 +29,8 @@ namespace mRemoteNG.UI.Controls.Base
|
||||
BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background");
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
|
||||
//Hide those nonthemable butons
|
||||
Controls[0].Hide();
|
||||
if (Controls.Count > 0)
|
||||
Controls[0].Hide();
|
||||
//Add new themable buttons
|
||||
Up = new NGButton
|
||||
{
|
||||
|
||||
@@ -15,12 +15,13 @@ using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.UI.Controls
|
||||
{
|
||||
public partial class ConnectionTree : TreeListView, IConnectionTree
|
||||
public partial class ConnectionTree : TreeListView, IConnectionTree
|
||||
{
|
||||
private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler();
|
||||
private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance;
|
||||
private readonly StatusImageList _statusImageList = new StatusImageList();
|
||||
private bool _nodeInEditMode;
|
||||
private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = new ConnectionTreeSearchTextFilter();
|
||||
private bool _nodeInEditMode;
|
||||
private bool _allowEdit;
|
||||
private ConnectionContextMenu _contextMenu;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
@@ -54,8 +55,6 @@ namespace mRemoteNG.UI.Controls
|
||||
UseOverlays = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
@@ -221,14 +220,19 @@ namespace mRemoteNG.UI.Controls
|
||||
return (RootNodeInfo)ConnectionTreeModel.RootNodes.First(item => item is RootNodeInfo);
|
||||
}
|
||||
|
||||
public void Invoke(Action action)
|
||||
{
|
||||
Invoke((Delegate)action);
|
||||
}
|
||||
|
||||
public void InvokeExpand(object model)
|
||||
{
|
||||
Invoke((MethodInvoker)(() => Expand(model)));
|
||||
Invoke(() => Expand(model));
|
||||
}
|
||||
|
||||
public void InvokeRebuildAll(bool preserveState)
|
||||
{
|
||||
Invoke((MethodInvoker)(() => RebuildAll(preserveState)));
|
||||
Invoke(() => RebuildAll(preserveState));
|
||||
}
|
||||
|
||||
public IEnumerable<RootPuttySessionsNodeInfo> GetRootPuttyNodes()
|
||||
@@ -262,6 +266,12 @@ namespace mRemoteNG.UI.Controls
|
||||
|
||||
private void AddNode(ConnectionInfo newNode)
|
||||
{
|
||||
if (SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttyRoot || SelectedNode?.GetTreeNodeType() == TreeNodeType.PuttySession)
|
||||
return;
|
||||
|
||||
// the new node will survive filtering if filtering is active
|
||||
_connectionTreeSearchTextFilter.SpecialInclusionList.Add(newNode);
|
||||
|
||||
// use root node if no node is selected
|
||||
ConnectionInfo parentNode = SelectedNode ?? GetRootConnectionNode();
|
||||
DefaultConnectionInfo.Instance.SaveTo(newNode);
|
||||
@@ -278,6 +288,13 @@ namespace mRemoteNG.UI.Controls
|
||||
|
||||
public void DuplicateSelectedNode()
|
||||
{
|
||||
if (SelectedNode == null)
|
||||
return;
|
||||
|
||||
var selectedNodeType = SelectedNode.GetTreeNodeType();
|
||||
if (selectedNodeType != TreeNodeType.Connection && selectedNodeType != TreeNodeType.Container)
|
||||
return;
|
||||
|
||||
var newNode = SelectedNode.Clone();
|
||||
SelectedNode.Parent.AddChildBelow(newNode, SelectedNode);
|
||||
newNode.Parent.SetChildBelow(newNode, SelectedNode);
|
||||
@@ -285,8 +302,11 @@ namespace mRemoteNG.UI.Controls
|
||||
|
||||
public void RenameSelectedNode()
|
||||
{
|
||||
_allowEdit = true;
|
||||
SelectedItem.BeginEdit();
|
||||
if (SelectedItem != null)
|
||||
{
|
||||
_allowEdit = true;
|
||||
SelectedItem.BeginEdit();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteSelectedNode()
|
||||
@@ -301,19 +321,75 @@ namespace mRemoteNG.UI.Controls
|
||||
if (sortTarget == null)
|
||||
sortTarget = GetRootConnectionNode();
|
||||
|
||||
Runtime.ConnectionsService.BeginBatchingSaves();
|
||||
|
||||
var sortTargetAsContainer = sortTarget as ContainerInfo;
|
||||
if (sortTargetAsContainer != null)
|
||||
sortTargetAsContainer.SortRecursive(sortDirection);
|
||||
else
|
||||
SelectedNode.Parent.SortRecursive(sortDirection);
|
||||
|
||||
Runtime.ConnectionsService.EndBatchingSaves();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands all tree objects and recalculates the
|
||||
/// column widths.
|
||||
/// </summary>
|
||||
public override void ExpandAll()
|
||||
{
|
||||
base.ExpandAll();
|
||||
AutoResizeColumn(Columns[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters tree items based on the given <see cref="filterText"/>
|
||||
/// </summary>
|
||||
/// <param name="filterText">The text to filter by</param>
|
||||
public void ApplyFilter(string filterText)
|
||||
{
|
||||
UseFiltering = true;
|
||||
_connectionTreeSearchTextFilter.FilterText = filterText;
|
||||
ModelFilter = _connectionTreeSearchTextFilter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all item filtering from the connection tree
|
||||
/// </summary>
|
||||
public void RemoveFilter()
|
||||
{
|
||||
UseFiltering = false;
|
||||
ResetColumnFiltering();
|
||||
}
|
||||
|
||||
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
RefreshObject(sender);
|
||||
// disable filtering if necessary. prevents RefreshObjects from
|
||||
// throwing an exception
|
||||
var filteringEnabled = IsFiltering;
|
||||
var filter = ModelFilter;
|
||||
if (filteringEnabled)
|
||||
{
|
||||
ResetColumnFiltering();
|
||||
}
|
||||
|
||||
RefreshObject(sender);
|
||||
AutoResizeColumn(Columns[0]);
|
||||
|
||||
// turn filtering back on
|
||||
if (filteringEnabled)
|
||||
{
|
||||
ModelFilter = filter;
|
||||
UpdateFiltering();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateFiltering()
|
||||
{
|
||||
base.UpdateFiltering();
|
||||
AutoResizeColumn(Columns[0]);
|
||||
}
|
||||
|
||||
private void tvConnections_AfterSelect(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -350,6 +426,13 @@ namespace mRemoteNG.UI.Controls
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Settings.Default.ShowDescriptionTooltipsInTree)
|
||||
{
|
||||
// setting text to null prevents the tooltip from being shown
|
||||
e.Text = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var nodeProducingTooltip = (ConnectionInfo)e.Model;
|
||||
e.Text = nodeProducingTooltip.Description;
|
||||
}
|
||||
@@ -385,6 +468,9 @@ namespace mRemoteNG.UI.Controls
|
||||
ConnectionTreeModel.RenameNode(SelectedNode, e.Label);
|
||||
_nodeInEditMode = false;
|
||||
_allowEdit = false;
|
||||
// ensures that if we are filtering and a new item is added that doesn't match the filter, it will be filtered out
|
||||
_connectionTreeSearchTextFilter.SpecialInclusionList.Clear();
|
||||
UpdateFiltering();
|
||||
Windows.ConfigForm.SelectedTreeNode = SelectedNode;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -394,4 +480,4 @@ namespace mRemoteNG.UI.Controls
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BrightIdeasSoftware;
|
||||
using System.Collections.Generic;
|
||||
using BrightIdeasSoftware;
|
||||
using mRemoteNG.Connection;
|
||||
|
||||
namespace mRemoteNG.UI.Controls
|
||||
@@ -7,12 +8,22 @@ namespace mRemoteNG.UI.Controls
|
||||
{
|
||||
public string FilterText { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// A list of <see cref="ConnectionInfo"/> objects that should
|
||||
/// always be included in the output, regardless of matching
|
||||
/// the desired <see cref="FilterText"/>.
|
||||
/// </summary>
|
||||
public List<ConnectionInfo> SpecialInclusionList { get; } = new List<ConnectionInfo>();
|
||||
|
||||
public bool Filter(object modelObject)
|
||||
{
|
||||
var objectAsConnectionInfo = modelObject as ConnectionInfo;
|
||||
if (objectAsConnectionInfo == null)
|
||||
return false;
|
||||
|
||||
if (SpecialInclusionList.Contains(objectAsConnectionInfo))
|
||||
return true;
|
||||
|
||||
var filterTextLower = FilterText.ToLowerInvariant();
|
||||
|
||||
if (objectAsConnectionInfo.Name.ToLowerInvariant().Contains(filterTextLower) ||
|
||||
|
||||
@@ -1,171 +1,263 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
|
||||
namespace mRemoteNG.UI.Controls.FilteredPropertyGrid
|
||||
{
|
||||
/// <summary>
|
||||
/// This class overrides the standard PropertyGrid provided by Microsoft.
|
||||
/// It also allows to hide (or filter) the properties of the SelectedObject displayed by the PropertyGrid.
|
||||
/// </summary>
|
||||
public partial class FilteredPropertyGrid : PropertyGrid
|
||||
/// <summary>
|
||||
/// This class overrides the standard PropertyGrid provided by Microsoft.
|
||||
/// It also allows to hide (or filter) the properties of the SelectedObject displayed by the PropertyGrid.
|
||||
/// </summary>
|
||||
public partial class FilteredPropertyGrid : PropertyGrid
|
||||
{
|
||||
/// <summary>Contain a reference to the collection of properties to show in the parent PropertyGrid.</summary>
|
||||
/// <summary>
|
||||
/// Contain a reference to the collection of properties to show in the parent PropertyGrid.
|
||||
/// </summary>
|
||||
/// <remarks>By default, m_PropertyDescriptors contain all the properties of the object. </remarks>
|
||||
readonly List<PropertyDescriptor> m_PropertyDescriptors = new List<PropertyDescriptor>();
|
||||
/// <summary>Contain a reference to the array of properties to display in the PropertyGrid.</summary>
|
||||
private AttributeCollection m_HiddenAttributes, m_BrowsableAttributes;
|
||||
/// <summary>Contain references to the arrays of properties or categories to hide.</summary>
|
||||
private string[] m_BrowsableProperties, m_HiddenProperties;
|
||||
/// <summary>Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid.</summary>
|
||||
private ObjectWrapper m_Wrapper;
|
||||
readonly List<PropertyDescriptor> _propertyDescriptors = new List<PropertyDescriptor>();
|
||||
|
||||
/// <summary>Public constructor.</summary>
|
||||
public FilteredPropertyGrid() {
|
||||
/// <summary>
|
||||
/// Contain a reference to the array of properties to display in the PropertyGrid.
|
||||
/// </summary>
|
||||
private AttributeCollection _hiddenAttributes;
|
||||
private AttributeCollection _browsableAttributes;
|
||||
|
||||
/// <summary>
|
||||
/// Contain references to the arrays of properties or categories to hide.
|
||||
/// </summary>
|
||||
private string[] _mBrowsableProperties;
|
||||
private string[] _mHiddenProperties;
|
||||
/// <summary>
|
||||
/// Contain a reference to the wrapper that contains the object to be displayed into the PropertyGrid.
|
||||
/// </summary>
|
||||
private ObjectWrapper _mWrapper;
|
||||
|
||||
/// <summary>
|
||||
/// Public constructor.
|
||||
/// </summary>
|
||||
public FilteredPropertyGrid()
|
||||
{
|
||||
InitializeComponent();
|
||||
base.SelectedObject = m_Wrapper;
|
||||
base.SelectedObject = _mWrapper;
|
||||
}
|
||||
|
||||
public new AttributeCollection BrowsableAttributes {
|
||||
get { return m_BrowsableAttributes; }
|
||||
/// <summary>
|
||||
/// A list of all currently properties being shown by the property grid.
|
||||
/// </summary>
|
||||
public IEnumerable<string> VisibleProperties => _propertyDescriptors.Select(p => p.Name);
|
||||
|
||||
public new AttributeCollection BrowsableAttributes {
|
||||
get { return _browsableAttributes; }
|
||||
set {
|
||||
if (m_BrowsableAttributes == value) return;
|
||||
m_HiddenAttributes = null;
|
||||
m_BrowsableAttributes = value;
|
||||
if (_browsableAttributes == value) return;
|
||||
_hiddenAttributes = null;
|
||||
_browsableAttributes = value;
|
||||
RefreshProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Get or set the categories to hide.</summary>
|
||||
/// <summary>
|
||||
/// Get or set the categories to hide.
|
||||
/// </summary>
|
||||
public AttributeCollection HiddenAttributes {
|
||||
get { return m_HiddenAttributes; }
|
||||
get { return _hiddenAttributes; }
|
||||
set {
|
||||
if (value == m_HiddenAttributes) return;
|
||||
m_HiddenAttributes = value;
|
||||
m_BrowsableAttributes = null;
|
||||
if (value == _hiddenAttributes) return;
|
||||
_hiddenAttributes = value;
|
||||
_browsableAttributes = null;
|
||||
RefreshProperties();
|
||||
}
|
||||
}
|
||||
/// <summary>Get or set the properties to show.</summary>
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the properties to show.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">if one or several properties don't exist.</exception>
|
||||
public string[] BrowsableProperties {
|
||||
get { return m_BrowsableProperties; }
|
||||
get { return _mBrowsableProperties; }
|
||||
set {
|
||||
if (value == m_BrowsableProperties) return;
|
||||
m_BrowsableProperties = value;
|
||||
//m_HiddenProperties = null;
|
||||
if (value == _mBrowsableProperties) return;
|
||||
_mBrowsableProperties = value;
|
||||
RefreshProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Get or set the properties to hide.</summary>
|
||||
public string[] HiddenProperties {
|
||||
get { return m_HiddenProperties; }
|
||||
get { return _mHiddenProperties; }
|
||||
set {
|
||||
if (value == m_HiddenProperties) return;
|
||||
//m_BrowsableProperties = null;
|
||||
m_HiddenProperties = value;
|
||||
if (value == _mHiddenProperties) return;
|
||||
_mHiddenProperties = value;
|
||||
RefreshProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Overwrite the PropertyGrid.SelectedObject property.</summary>
|
||||
/// <summary>
|
||||
/// Overwrite the PropertyGrid.SelectedObject property.
|
||||
/// </summary>
|
||||
/// <remarks>The object passed to the base PropertyGrid is the wrapper.</remarks>
|
||||
public new object SelectedObject {
|
||||
get { return m_Wrapper != null ? ((ObjectWrapper)base.SelectedObject).SelectedObject : null; }
|
||||
get
|
||||
{
|
||||
return _mWrapper != null
|
||||
? ((ObjectWrapper)base.SelectedObject).SelectedObject
|
||||
: null;
|
||||
}
|
||||
set {
|
||||
// Set the new object to the wrapper and create one if necessary.
|
||||
if(m_Wrapper == null) {
|
||||
m_Wrapper = new ObjectWrapper(value);
|
||||
if(_mWrapper == null)
|
||||
{
|
||||
_mWrapper = new ObjectWrapper(value);
|
||||
RefreshProperties();
|
||||
}
|
||||
else if(m_Wrapper.SelectedObject != value) {
|
||||
var needrefresh = value.GetType() != m_Wrapper.SelectedObject.GetType();
|
||||
m_Wrapper.SelectedObject = value;
|
||||
if(needrefresh) RefreshProperties();
|
||||
else if(_mWrapper.SelectedObject != value)
|
||||
{
|
||||
var needrefresh = value.GetType() != _mWrapper.SelectedObject.GetType();
|
||||
_mWrapper.SelectedObject = value;
|
||||
if(needrefresh)
|
||||
RefreshProperties();
|
||||
}
|
||||
// Set the list of properties to the wrapper.
|
||||
m_Wrapper.PropertyDescriptors = m_PropertyDescriptors;
|
||||
_mWrapper.PropertyDescriptors = _propertyDescriptors;
|
||||
// Link the wrapper to the parent PropertyGrid.
|
||||
base.SelectedObject = m_Wrapper;
|
||||
base.SelectedObject = _mWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>Called when the browsable properties have changed.</summary>
|
||||
private void OnBrowsablePropertiesChanged() {
|
||||
if(m_Wrapper == null) return;
|
||||
}
|
||||
*/
|
||||
/// <summary>
|
||||
/// Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties.
|
||||
/// </summary>
|
||||
private void RefreshProperties()
|
||||
{
|
||||
if(_mWrapper == null)
|
||||
return;
|
||||
|
||||
/// <summary>Build the list of the properties to be displayed in the PropertyGrid, following the filters defined the Browsable and Hidden properties.</summary>
|
||||
private void RefreshProperties() {
|
||||
if(m_Wrapper == null) return;
|
||||
// Clear the list of properties to be displayed.
|
||||
m_PropertyDescriptors.Clear();
|
||||
_propertyDescriptors.Clear();
|
||||
// Check whether the list is filtered
|
||||
if(m_BrowsableAttributes != null && m_BrowsableAttributes.Count > 0) {
|
||||
if(_browsableAttributes != null && _browsableAttributes.Count > 0)
|
||||
{
|
||||
// Add to the list the attributes that need to be displayed.
|
||||
foreach(Attribute attribute in m_BrowsableAttributes) ShowAttribute(attribute);
|
||||
} else {
|
||||
// Fill the collection with all the properties.
|
||||
var originalpropertydescriptors = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject);
|
||||
foreach(PropertyDescriptor propertydescriptor in originalpropertydescriptors) m_PropertyDescriptors.Add(propertydescriptor);
|
||||
// Remove from the list the attributes that mustn't be displayed.
|
||||
if(m_HiddenAttributes != null) foreach(Attribute attribute in m_HiddenAttributes) HideAttribute(attribute);
|
||||
foreach(Attribute attribute in _browsableAttributes)
|
||||
ShowAttribute(attribute);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fill the collection with all the properties.
|
||||
var originalPropertyDescriptors = TypeDescriptor
|
||||
.GetProperties(_mWrapper.SelectedObject)
|
||||
.OfType<PropertyDescriptor>()
|
||||
.Where(PropertyDoesntHaveBrowsableFalseAttribute);
|
||||
|
||||
foreach(PropertyDescriptor propertyDescriptor in originalPropertyDescriptors)
|
||||
_propertyDescriptors.Add(propertyDescriptor);
|
||||
|
||||
// Remove from the list the attributes that mustn't be displayed.
|
||||
if(_hiddenAttributes != null)
|
||||
foreach (Attribute attribute in _hiddenAttributes)
|
||||
HideAttribute(attribute);
|
||||
}
|
||||
|
||||
// Get all the properties of the SelectedObject
|
||||
var allproperties = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject);
|
||||
// Hide if necessary, some properties
|
||||
if(m_HiddenProperties != null && m_HiddenProperties.Length > 0) {
|
||||
var allproperties = TypeDescriptor.GetProperties(_mWrapper.SelectedObject);
|
||||
|
||||
// Hide if necessary, some properties
|
||||
if(_mHiddenProperties != null && _mHiddenProperties.Length > 0)
|
||||
{
|
||||
// Remove from the list the properties that mustn't be displayed.
|
||||
foreach(var propertyname in m_HiddenProperties) {
|
||||
try {
|
||||
foreach(var propertyname in _mHiddenProperties)
|
||||
{
|
||||
try
|
||||
{
|
||||
var property = allproperties[propertyname];
|
||||
// Remove from the list the property
|
||||
HideProperty(property);
|
||||
} catch(Exception ex) {
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Could not hide Property.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display if necessary, some properties
|
||||
if(m_BrowsableProperties != null && m_BrowsableProperties.Length > 0) {
|
||||
foreach(var propertyname in m_BrowsableProperties) {
|
||||
try {
|
||||
if(_mBrowsableProperties != null && _mBrowsableProperties.Length > 0)
|
||||
{
|
||||
foreach(var propertyname in _mBrowsableProperties)
|
||||
{
|
||||
try
|
||||
{
|
||||
ShowProperty(allproperties[propertyname]);
|
||||
} catch(Exception knfe) {
|
||||
Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Property not found", knfe);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage("FilteredPropertyGrid: Property not found", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>Allows to hide a set of properties to the parent PropertyGrid.</summary>
|
||||
|
||||
/// <summary>
|
||||
/// Predicate to determine if a property has a Browsable(false) attribute
|
||||
/// attatched to it. If so, it should not be shown.
|
||||
/// </summary>
|
||||
/// <param name="propertyDescriptor"></param>
|
||||
/// <returns></returns>
|
||||
private bool PropertyDoesntHaveBrowsableFalseAttribute(PropertyDescriptor propertyDescriptor)
|
||||
{
|
||||
return !propertyDescriptor.Attributes.Contains(new BrowsableAttribute(false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows to hide a set of properties to the parent PropertyGrid.
|
||||
/// </summary>
|
||||
/// <param name="attribute">A set of attributes that filter the original collection of properties.</param>
|
||||
/// <remarks>For better performance, include the BrowsableAttribute with true value.</remarks>
|
||||
private void HideAttribute(Attribute attribute) {
|
||||
var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject,new[] { attribute });
|
||||
if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) throw new ArgumentException("Attribute not found",attribute.ToString());
|
||||
foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) HideProperty(propertydescriptor);
|
||||
private void HideAttribute(Attribute attribute)
|
||||
{
|
||||
var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(_mWrapper.SelectedObject,new[] { attribute });
|
||||
if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0)
|
||||
throw new ArgumentException("Attribute not found", attribute.ToString());
|
||||
|
||||
foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors)
|
||||
HideProperty(propertydescriptor);
|
||||
}
|
||||
/// <summary>Add all the properties that match an attribute to the list of properties to be displayed in the PropertyGrid.</summary>
|
||||
|
||||
/// <summary>
|
||||
/// Add all the properties that match an attribute to the list of properties to be displayed in the PropertyGrid.
|
||||
/// </summary>
|
||||
/// <param name="attribute">The attribute to be added.</param>
|
||||
private void ShowAttribute(Attribute attribute) {
|
||||
var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(m_Wrapper.SelectedObject,new[] { attribute });
|
||||
if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0) throw new ArgumentException("Attribute not found",attribute.ToString());
|
||||
foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors) ShowProperty(propertydescriptor);
|
||||
private void ShowAttribute(Attribute attribute)
|
||||
{
|
||||
var filteredoriginalpropertydescriptors = TypeDescriptor.GetProperties(_mWrapper.SelectedObject,new[] { attribute });
|
||||
if(filteredoriginalpropertydescriptors == null || filteredoriginalpropertydescriptors.Count == 0)
|
||||
throw new ArgumentException("Attribute not found", attribute.ToString());
|
||||
|
||||
foreach(PropertyDescriptor propertydescriptor in filteredoriginalpropertydescriptors)
|
||||
ShowProperty(propertydescriptor);
|
||||
}
|
||||
/// <summary>Add a property to the list of properties to be displayed in the PropertyGrid.</summary>
|
||||
|
||||
/// <summary>
|
||||
/// Add a property to the list of properties to be displayed in the PropertyGrid.
|
||||
/// </summary>
|
||||
/// <param name="property">The property to be added.</param>
|
||||
private void ShowProperty(PropertyDescriptor property) {
|
||||
if(!m_PropertyDescriptors.Contains(property)) m_PropertyDescriptors.Add(property);
|
||||
private void ShowProperty(PropertyDescriptor property)
|
||||
{
|
||||
if(!_propertyDescriptors.Contains(property))
|
||||
_propertyDescriptors.Add(property);
|
||||
}
|
||||
/// <summary>Allows to hide a property to the parent PropertyGrid.</summary>
|
||||
|
||||
/// <summary>
|
||||
/// Allows to hide a property to the parent PropertyGrid.
|
||||
/// </summary>
|
||||
/// <param name="property">The name of the property to be hidden.</param>
|
||||
private void HideProperty(PropertyDescriptor property) {
|
||||
if(m_PropertyDescriptors.Contains(property)) m_PropertyDescriptors.Remove(property);
|
||||
private void HideProperty(PropertyDescriptor property)
|
||||
{
|
||||
if(_propertyDescriptors.Contains(property))
|
||||
_propertyDescriptors.Remove(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,96 +4,119 @@ using System.ComponentModel;
|
||||
|
||||
namespace mRemoteNG.UI.Controls.FilteredPropertyGrid
|
||||
{
|
||||
/// <summary>This class is a wrapper. It contains the object the propertyGrid has to display.</summary>
|
||||
internal class ObjectWrapper : ICustomTypeDescriptor
|
||||
/// <summary>
|
||||
/// This class is a wrapper. It contains the object the PropertyGrid has to display.
|
||||
/// </summary>
|
||||
internal class ObjectWrapper : ICustomTypeDescriptor
|
||||
{
|
||||
/// <summary>Contain a reference to the selected objet that will linked to the parent PropertyGrid.</summary>
|
||||
private object m_SelectedObject;
|
||||
/// <summary>Contain a reference to the collection of properties to show in the parent PropertyGrid.</summary>
|
||||
/// <remarks>By default, m_PropertyDescriptors contain all the properties of the object. </remarks>
|
||||
List<PropertyDescriptor> m_PropertyDescriptors = new List<PropertyDescriptor>();
|
||||
|
||||
/// <summary>Simple constructor.</summary>
|
||||
/// <summary>
|
||||
/// Creates a new instance of an <see cref="ObjectWrapper"/> with the given object to be wrapped.
|
||||
/// </summary>
|
||||
/// <param name="obj">A reference to the selected object that will linked to the parent PropertyGrid.</param>
|
||||
internal ObjectWrapper(object obj) {
|
||||
m_SelectedObject = obj;
|
||||
internal ObjectWrapper(object obj)
|
||||
{
|
||||
SelectedObject = obj;
|
||||
}
|
||||
|
||||
/// <summary>Get or set a reference to the selected objet that will linked to the parent PropertyGrid.</summary>
|
||||
public object SelectedObject {
|
||||
get { return m_SelectedObject; }
|
||||
set { m_SelectedObject = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get or set a reference to the selected objet that will linked to the parent PropertyGrid.
|
||||
/// </summary>
|
||||
public object SelectedObject { get; set; }
|
||||
|
||||
/// <summary>Get or set a reference to the collection of properties to show in the parent PropertyGrid.</summary>
|
||||
public List<PropertyDescriptor> PropertyDescriptors {
|
||||
get { return m_PropertyDescriptors; }
|
||||
set { m_PropertyDescriptors = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get or set a reference to the collection of properties to show in the parent PropertyGrid
|
||||
/// </summary>
|
||||
public List<PropertyDescriptor> PropertyDescriptors { get; set; } = new List<PropertyDescriptor>();
|
||||
|
||||
#region ICustomTypeDescriptor Members
|
||||
public PropertyDescriptorCollection GetProperties(Attribute[] attributes) {
|
||||
#region ICustomTypeDescriptor Members
|
||||
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
|
||||
{
|
||||
return GetProperties();
|
||||
}
|
||||
|
||||
public PropertyDescriptorCollection GetProperties() {
|
||||
return new PropertyDescriptorCollection(m_PropertyDescriptors.ToArray(),true);
|
||||
public PropertyDescriptorCollection GetProperties()
|
||||
{
|
||||
return new PropertyDescriptorCollection(PropertyDescriptors.ToArray(), true);
|
||||
}
|
||||
|
||||
/// <summary>GetAttributes.</summary>
|
||||
/// <summary>
|
||||
/// GetAttributes
|
||||
/// </summary>
|
||||
/// <returns>AttributeCollection</returns>
|
||||
public AttributeCollection GetAttributes() {
|
||||
return TypeDescriptor.GetAttributes(m_SelectedObject,true);
|
||||
}
|
||||
/// <summary>Get Class Name.</summary>
|
||||
/// <returns>String</returns>
|
||||
public String GetClassName() {
|
||||
return TypeDescriptor.GetClassName(m_SelectedObject,true);
|
||||
}
|
||||
/// <summary>GetComponentName.</summary>
|
||||
/// <returns>String</returns>
|
||||
public String GetComponentName() {
|
||||
return TypeDescriptor.GetComponentName(m_SelectedObject,true);
|
||||
public AttributeCollection GetAttributes()
|
||||
{
|
||||
return TypeDescriptor.GetAttributes(SelectedObject, true);
|
||||
}
|
||||
|
||||
/// <summary>GetConverter.</summary>
|
||||
/// <summary>
|
||||
/// Get Class Name
|
||||
/// </summary>
|
||||
/// <returns>String</returns>
|
||||
public string GetClassName()
|
||||
{
|
||||
return TypeDescriptor.GetClassName(SelectedObject, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetComponentName
|
||||
/// </summary>
|
||||
/// <returns>String</returns>
|
||||
public string GetComponentName()
|
||||
{
|
||||
return TypeDescriptor.GetComponentName(SelectedObject, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetConverter
|
||||
/// </summary>
|
||||
/// <returns>TypeConverter</returns>
|
||||
public TypeConverter GetConverter() {
|
||||
return TypeDescriptor.GetConverter(m_SelectedObject,true);
|
||||
public TypeConverter GetConverter()
|
||||
{
|
||||
return TypeDescriptor.GetConverter(SelectedObject, true);
|
||||
}
|
||||
|
||||
/// <summary>GetDefaultEvent.</summary>
|
||||
/// <summary>
|
||||
/// GetDefaultEvent
|
||||
/// </summary>
|
||||
/// <returns>EventDescriptor</returns>
|
||||
public EventDescriptor GetDefaultEvent() {
|
||||
return TypeDescriptor.GetDefaultEvent(m_SelectedObject,true);
|
||||
public EventDescriptor GetDefaultEvent()
|
||||
{
|
||||
return TypeDescriptor.GetDefaultEvent(SelectedObject, true);
|
||||
}
|
||||
|
||||
/// <summary>GetDefaultProperty.</summary>
|
||||
/// <summary>
|
||||
/// GetDefaultProperty
|
||||
/// </summary>
|
||||
/// <returns>PropertyDescriptor</returns>
|
||||
public PropertyDescriptor GetDefaultProperty() {
|
||||
return TypeDescriptor.GetDefaultProperty(m_SelectedObject,true);
|
||||
public PropertyDescriptor GetDefaultProperty()
|
||||
{
|
||||
return TypeDescriptor.GetDefaultProperty(SelectedObject, true);
|
||||
}
|
||||
|
||||
/// <summary>GetEditor.</summary>
|
||||
/// <summary>
|
||||
/// GetEditor
|
||||
/// </summary>
|
||||
/// <param name="editorBaseType">editorBaseType</param>
|
||||
/// <returns>object</returns>
|
||||
public object GetEditor(Type editorBaseType) {
|
||||
return TypeDescriptor.GetEditor(this,editorBaseType,true);
|
||||
public object GetEditor(Type editorBaseType)
|
||||
{
|
||||
return TypeDescriptor.GetEditor(this,editorBaseType, true);
|
||||
}
|
||||
|
||||
public EventDescriptorCollection GetEvents(Attribute[] attributes) {
|
||||
return TypeDescriptor.GetEvents(m_SelectedObject,attributes,true);
|
||||
public EventDescriptorCollection GetEvents(Attribute[] attributes)
|
||||
{
|
||||
return TypeDescriptor.GetEvents(SelectedObject, attributes, true);
|
||||
}
|
||||
|
||||
public EventDescriptorCollection GetEvents() {
|
||||
return TypeDescriptor.GetEvents(m_SelectedObject,true);
|
||||
public EventDescriptorCollection GetEvents()
|
||||
{
|
||||
return TypeDescriptor.GetEvents(SelectedObject, true);
|
||||
}
|
||||
|
||||
public object GetPropertyOwner(PropertyDescriptor pd) {
|
||||
return m_SelectedObject;
|
||||
public object GetPropertyOwner(PropertyDescriptor pd)
|
||||
{
|
||||
return SelectedObject;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,8 @@ namespace mRemoteNG.UI.Controls
|
||||
/** Sets and Gets the tooltiptext on toolTip1 */
|
||||
public string ToolTipText
|
||||
{
|
||||
get
|
||||
{ return toolTip1.GetToolTip(Octet1); }
|
||||
set
|
||||
get => toolTip1.GetToolTip(Octet1);
|
||||
set
|
||||
{
|
||||
toolTip1.SetToolTip(Octet1,value);
|
||||
toolTip1.SetToolTip(Octet2,value);
|
||||
@@ -46,12 +45,8 @@ namespace mRemoteNG.UI.Controls
|
||||
/** Set or Get the string that represents the value in the box */
|
||||
public override string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return Octet1.Text + @"." + Octet2.Text + @"." + Octet3.Text + @"." + Octet4.Text;
|
||||
|
||||
}
|
||||
set
|
||||
get => Octet1.Text + @"." + Octet2.Text + @"." + Octet3.Text + @"." + Octet4.Text;
|
||||
set
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
@@ -245,7 +240,7 @@ namespace mRemoteNG.UI.Controls
|
||||
if(theValue >=0 && theValue <= 255)
|
||||
return true;
|
||||
|
||||
MessageBox.Show("Must Be Between 0 and 255","Out Of Range");
|
||||
MessageBox.Show(Language.strIPRange,Language.strOutOfRange);
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Themes;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.UI.Controls
|
||||
@@ -10,12 +11,16 @@ namespace mRemoteNG.UI.Controls
|
||||
private ToolStripLabel _lblMultiSsh;
|
||||
private ToolStripTextBox _txtMultiSsh;
|
||||
private MultiSSHController _multiSshController;
|
||||
private ThemeManager _themeManager;
|
||||
|
||||
|
||||
public MultiSshToolStrip()
|
||||
public MultiSshToolStrip()
|
||||
{
|
||||
InitializeComponent();
|
||||
_multiSshController = new MultiSSHController(_txtMultiSsh);
|
||||
_themeManager = ThemeManager.getInstance();
|
||||
_themeManager.ThemeChanged += ApplyTheme;
|
||||
ApplyTheme();
|
||||
_multiSshController = new MultiSSHController(_txtMultiSsh);
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
@@ -43,7 +48,14 @@ namespace mRemoteNG.UI.Controls
|
||||
ResumeLayout(true);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
private void ApplyTheme()
|
||||
{
|
||||
if (!_themeManager.ThemingActive) return;
|
||||
_txtMultiSsh.BackColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Background");
|
||||
_txtMultiSsh.ForeColor = _themeManager.ActiveTheme.ExtendedPalette.getColor("TextBox_Foreground");
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
using System.Windows.Forms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
namespace mRemoteNG.UI
|
||||
{
|
||||
@@ -15,5 +20,86 @@ namespace mRemoteNG.UI
|
||||
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and shows a dialog to either create a new connections file, load a different one,
|
||||
/// exit, or optionally cancel the operation.
|
||||
/// </summary>
|
||||
/// <param name="connectionFileName"></param>
|
||||
/// <param name="messageText"></param>
|
||||
/// <param name="showCancelButton"></param>
|
||||
public static void ShowLoadConnectionsFailedDialog(string connectionFileName, string messageText, bool showCancelButton)
|
||||
{
|
||||
var commandButtons = new List<string>
|
||||
{
|
||||
Language.ConfigurationCreateNew,
|
||||
Language.strOpenADifferentFile,
|
||||
Language.strMenuExit
|
||||
};
|
||||
|
||||
if (showCancelButton)
|
||||
commandButtons.Add(Language.strButtonCancel);
|
||||
|
||||
var answered = false;
|
||||
while (!answered)
|
||||
{
|
||||
try
|
||||
{
|
||||
CTaskDialog.ShowTaskDialogBox(
|
||||
GeneralAppInfo.ProductName,
|
||||
messageText,
|
||||
"", "", "", "", "",
|
||||
string.Join(" | ", commandButtons),
|
||||
ETaskDialogButtons.None,
|
||||
ESysIcons.Question,
|
||||
ESysIcons.Question);
|
||||
|
||||
switch (CTaskDialog.CommandButtonResult)
|
||||
{
|
||||
case 0: // New
|
||||
var saveAsDialog = ConnectionsSaveAsDialog();
|
||||
saveAsDialog.ShowDialog();
|
||||
Runtime.ConnectionsService.NewConnectionsFile(saveAsDialog.FileName);
|
||||
answered = true;
|
||||
break;
|
||||
case 1: // Load
|
||||
Runtime.LoadConnections(true);
|
||||
answered = true;
|
||||
break;
|
||||
case 2: // Exit
|
||||
Application.Exit();
|
||||
answered = true;
|
||||
break;
|
||||
case 3: // Cancel
|
||||
answered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(
|
||||
string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionFileName),
|
||||
exception,
|
||||
MessageClass.WarningMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new dialog that allows the user to select an mRemoteNG
|
||||
/// connections file path. Don't forget to dispose the dialog when you
|
||||
/// are done!
|
||||
/// </summary>
|
||||
public static SaveFileDialog ConnectionsSaveAsDialog()
|
||||
{
|
||||
return new SaveFileDialog
|
||||
{
|
||||
CheckPathExists = true,
|
||||
InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath,
|
||||
FileName = ConnectionsFileInfo.DefaultConnectionsFile,
|
||||
OverwritePrompt = true,
|
||||
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
48
mRemoteV1/UI/Forms/ExportForm.Designer.cs
generated
48
mRemoteV1/UI/Forms/ExportForm.Designer.cs
generated
@@ -9,27 +9,27 @@ namespace mRemoteNG.UI.Forms
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnCancel = new Controls.Base.NGButton();
|
||||
this.btnOK = new Controls.Base.NGButton();
|
||||
this.lblUncheckProperties = new Controls.Base.NGLabel();
|
||||
this.chkUsername = new Controls.Base.NGCheckBox();
|
||||
this.chkPassword = new Controls.Base.NGCheckBox();
|
||||
this.chkDomain = new Controls.Base.NGCheckBox();
|
||||
this.chkInheritance = new Controls.Base.NGCheckBox();
|
||||
this.txtFileName = new Controls.Base.NGTextBox();
|
||||
this.btnBrowse = new Controls.Base.NGButton();
|
||||
this.btnCancel = new mRemoteNG.UI.Controls.Base.NGButton();
|
||||
this.btnOK = new mRemoteNG.UI.Controls.Base.NGButton();
|
||||
this.lblUncheckProperties = new mRemoteNG.UI.Controls.Base.NGLabel();
|
||||
this.chkUsername = new mRemoteNG.UI.Controls.Base.NGCheckBox();
|
||||
this.chkPassword = new mRemoteNG.UI.Controls.Base.NGCheckBox();
|
||||
this.chkDomain = new mRemoteNG.UI.Controls.Base.NGCheckBox();
|
||||
this.chkInheritance = new mRemoteNG.UI.Controls.Base.NGCheckBox();
|
||||
this.txtFileName = new mRemoteNG.UI.Controls.Base.NGTextBox();
|
||||
this.btnBrowse = new mRemoteNG.UI.Controls.Base.NGButton();
|
||||
this.grpProperties = new System.Windows.Forms.GroupBox();
|
||||
this.chkAssignedCredential = new Controls.Base.NGCheckBox();
|
||||
this.chkAssignedCredential = new mRemoteNG.UI.Controls.Base.NGCheckBox();
|
||||
this.grpFile = new System.Windows.Forms.GroupBox();
|
||||
this.lblFileFormat = new Controls.Base.NGLabel();
|
||||
this.lblFileName = new Controls.Base.NGLabel();
|
||||
this.cboFileFormat = new Controls.Base.NGComboBox();
|
||||
this.lblFileFormat = new mRemoteNG.UI.Controls.Base.NGLabel();
|
||||
this.lblFileName = new mRemoteNG.UI.Controls.Base.NGLabel();
|
||||
this.cboFileFormat = new mRemoteNG.UI.Controls.Base.NGComboBox();
|
||||
this.grpItems = new System.Windows.Forms.GroupBox();
|
||||
this.lblSelectedConnection = new Controls.Base.NGLabel();
|
||||
this.lblSelectedFolder = new Controls.Base.NGLabel();
|
||||
this.rdoExportSelectedConnection = new Controls.Base.NGRadioButton();
|
||||
this.rdoExportSelectedFolder = new Controls.Base.NGRadioButton();
|
||||
this.rdoExportEverything = new Controls.Base.NGRadioButton();
|
||||
this.lblSelectedConnection = new mRemoteNG.UI.Controls.Base.NGLabel();
|
||||
this.lblSelectedFolder = new mRemoteNG.UI.Controls.Base.NGLabel();
|
||||
this.rdoExportSelectedConnection = new mRemoteNG.UI.Controls.Base.NGRadioButton();
|
||||
this.rdoExportSelectedFolder = new mRemoteNG.UI.Controls.Base.NGRadioButton();
|
||||
this.rdoExportEverything = new mRemoteNG.UI.Controls.Base.NGRadioButton();
|
||||
this.grpProperties.SuspendLayout();
|
||||
this.grpFile.SuspendLayout();
|
||||
this.grpItems.SuspendLayout();
|
||||
@@ -37,6 +37,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER;
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(447, 473);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
@@ -48,6 +49,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// btnOK
|
||||
//
|
||||
this.btnOK._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER;
|
||||
this.btnOK.Location = new System.Drawing.Point(366, 473);
|
||||
this.btnOK.Name = "btnOK";
|
||||
this.btnOK.Size = new System.Drawing.Size(75, 23);
|
||||
@@ -67,6 +69,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// chkUsername
|
||||
//
|
||||
this.chkUsername._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
|
||||
this.chkUsername.AutoSize = true;
|
||||
this.chkUsername.Checked = true;
|
||||
this.chkUsername.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
@@ -79,6 +82,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// chkPassword
|
||||
//
|
||||
this.chkPassword._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
|
||||
this.chkPassword.AutoSize = true;
|
||||
this.chkPassword.Checked = true;
|
||||
this.chkPassword.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
@@ -91,6 +95,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// chkDomain
|
||||
//
|
||||
this.chkDomain._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
|
||||
this.chkDomain.AutoSize = true;
|
||||
this.chkDomain.Checked = true;
|
||||
this.chkDomain.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
@@ -103,6 +108,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// chkInheritance
|
||||
//
|
||||
this.chkInheritance._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
|
||||
this.chkInheritance.AutoSize = true;
|
||||
this.chkInheritance.Checked = true;
|
||||
this.chkInheritance.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
@@ -124,6 +130,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// btnBrowse
|
||||
//
|
||||
this.btnBrowse._mice = mRemoteNG.UI.Controls.Base.NGButton.MouseState.HOVER;
|
||||
this.btnBrowse.Location = new System.Drawing.Point(417, 46);
|
||||
this.btnBrowse.Name = "btnBrowse";
|
||||
this.btnBrowse.Size = new System.Drawing.Size(75, 23);
|
||||
@@ -149,6 +156,7 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// chkAssignedCredential
|
||||
//
|
||||
this.chkAssignedCredential._mice = mRemoteNG.UI.Controls.Base.NGCheckBox.MouseState.HOVER;
|
||||
this.chkAssignedCredential.AutoSize = true;
|
||||
this.chkAssignedCredential.Checked = true;
|
||||
this.chkAssignedCredential.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
@@ -158,6 +166,7 @@ namespace mRemoteNG.UI.Forms
|
||||
this.chkAssignedCredential.TabIndex = 5;
|
||||
this.chkAssignedCredential.Text = "Assigned Credential";
|
||||
this.chkAssignedCredential.UseVisualStyleBackColor = true;
|
||||
this.chkAssignedCredential.Visible = false;
|
||||
//
|
||||
// grpFile
|
||||
//
|
||||
@@ -193,7 +202,8 @@ namespace mRemoteNG.UI.Forms
|
||||
//
|
||||
// cboFileFormat
|
||||
//
|
||||
this.cboFileFormat.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
this.cboFileFormat._mice = mRemoteNG.UI.Controls.Base.NGComboBox.MouseState.HOVER;
|
||||
this.cboFileFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cboFileFormat.FormattingEnabled = true;
|
||||
this.cboFileFormat.Location = new System.Drawing.Point(15, 100);
|
||||
this.cboFileFormat.Name = "cboFileFormat";
|
||||
|
||||
@@ -226,20 +226,21 @@ namespace mRemoteNG.UI.Forms
|
||||
|
||||
private void cboFileformat_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (SaveFormat == SaveFormat.mRXML)
|
||||
{
|
||||
chkUsername.Enabled = false;
|
||||
chkPassword.Enabled = false;
|
||||
chkDomain.Enabled = false;
|
||||
chkAssignedCredential.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
chkUsername.Enabled = true;
|
||||
chkPassword.Enabled = true;
|
||||
chkDomain.Enabled = true;
|
||||
chkAssignedCredential.Enabled = false;
|
||||
}
|
||||
// should only be active if we are using the credential manager feature
|
||||
//if (SaveFormat == SaveFormat.mRXML)
|
||||
//{
|
||||
// chkUsername.Enabled = false;
|
||||
// chkPassword.Enabled = false;
|
||||
// chkDomain.Enabled = false;
|
||||
// chkAssignedCredential.Enabled = true;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// chkUsername.Enabled = true;
|
||||
// chkPassword.Enabled = true;
|
||||
// chkDomain.Enabled = true;
|
||||
// chkAssignedCredential.Enabled = false;
|
||||
//}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -28,13 +28,13 @@ namespace mRemoteNG.UI.Forms.Input
|
||||
textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
|
||||
textBox.SetBounds(12, 36, 372, 20);
|
||||
|
||||
buttonOk.Text = "OK";
|
||||
buttonOk.Text = Language.strButtonOK;
|
||||
buttonOk.DialogResult = DialogResult.OK;
|
||||
buttonOk.FlatStyle = FlatStyle.Flat;
|
||||
buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
buttonOk.SetBounds(228, 72, 75, 23);
|
||||
|
||||
buttonCancel.Text = "Cancel";
|
||||
buttonCancel.Text = Language.strButtonCancel;
|
||||
buttonCancel.DialogResult = DialogResult.Cancel;
|
||||
buttonCancel.FlatStyle = FlatStyle.Flat;
|
||||
buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
public partial class AdvancedPage : OptionsPage
|
||||
public sealed partial class AdvancedPage : OptionsPage
|
||||
{
|
||||
//UserControl overrides dispose to clean up the component list.
|
||||
[System.Diagnostics.DebuggerNonUserCode()]
|
||||
|
||||
@@ -9,19 +9,19 @@ using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
public partial class AdvancedPage
|
||||
public sealed partial class AdvancedPage
|
||||
{
|
||||
public AdvancedPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
base.ApplyTheme();
|
||||
ApplyTheme();
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override string PageName
|
||||
{
|
||||
get { return Language.strTabAdvanced; }
|
||||
get => Language.strTabAdvanced;
|
||||
set { }
|
||||
}
|
||||
|
||||
@@ -108,16 +108,14 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
using (var openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
openFileDialog.Filter = $"{Language.strFilterApplication}|*.exe|{Language.strFilterAll}|*.*";
|
||||
openFileDialog.Filter = $@"{Language.strFilterApplication}|*.exe|{Language.strFilterAll}|*.*";
|
||||
openFileDialog.FileName = Path.GetFileName(GeneralAppInfo.PuttyPath);
|
||||
openFileDialog.CheckFileExists = true;
|
||||
openFileDialog.Multiselect = false;
|
||||
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
txtCustomPuttyPath.Text = openFileDialog.FileName;
|
||||
SetPuttyLaunchButtonEnabled();
|
||||
}
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK) return;
|
||||
txtCustomPuttyPath.Text = openFileDialog.FileName;
|
||||
SetPuttyLaunchButtonEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
|
||||
public partial class AppearancePage : OptionsPage
|
||||
public sealed partial class AppearancePage : OptionsPage
|
||||
{
|
||||
|
||||
//UserControl overrides dispose to clean up the component list.
|
||||
|
||||
@@ -5,17 +5,17 @@ using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
public partial class AppearancePage
|
||||
public sealed partial class AppearancePage
|
||||
{
|
||||
public AppearancePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
base.ApplyTheme();
|
||||
ApplyTheme();
|
||||
}
|
||||
|
||||
public override string PageName
|
||||
{
|
||||
get { return Language.strTabAppearance; }
|
||||
get => Language.strTabAppearance;
|
||||
set { }
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
|
||||
public partial class ConnectionsPage : OptionsPage
|
||||
public sealed partial class ConnectionsPage : OptionsPage
|
||||
{
|
||||
|
||||
//UserControl overrides dispose to clean up the component list.
|
||||
|
||||
@@ -3,19 +3,19 @@ using mRemoteNG.Config;
|
||||
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
public partial class ConnectionsPage
|
||||
public sealed partial class ConnectionsPage
|
||||
{
|
||||
private FrmMain _frmMain = FrmMain.Default;
|
||||
private readonly FrmMain _frmMain = FrmMain.Default;
|
||||
|
||||
public ConnectionsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
base.ApplyTheme();
|
||||
ApplyTheme();
|
||||
}
|
||||
|
||||
public override string PageName
|
||||
{
|
||||
get { return Language.strConnections; }
|
||||
get => Language.strConnections;
|
||||
set { }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
partial class CredentialsPage
|
||||
sealed partial class CredentialsPage
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
|
||||
@@ -4,16 +4,16 @@ using mRemoteNG.Security.SymmetricEncryption;
|
||||
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
public partial class CredentialsPage : OptionsPage
|
||||
public sealed partial class CredentialsPage : OptionsPage
|
||||
{
|
||||
public CredentialsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
base.ApplyTheme();
|
||||
ApplyTheme();
|
||||
}
|
||||
|
||||
public override string PageName {
|
||||
get { return Language.Credentials; }
|
||||
get => Language.Credentials;
|
||||
set { }
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
|
||||
public partial class NotificationsPage : OptionsPage
|
||||
public sealed partial class NotificationsPage : OptionsPage
|
||||
{
|
||||
|
||||
//UserControl overrides dispose to clean up the component list.
|
||||
|
||||
@@ -5,17 +5,17 @@ using mRemoteNG.App;
|
||||
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
public partial class NotificationsPage
|
||||
public sealed partial class NotificationsPage
|
||||
{
|
||||
public NotificationsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
base.ApplyTheme();
|
||||
ApplyTheme();
|
||||
}
|
||||
|
||||
public override string PageName
|
||||
{
|
||||
get { return Language.strMenuNotifications; }
|
||||
get => Language.strMenuNotifications;
|
||||
set { }
|
||||
}
|
||||
|
||||
|
||||
@@ -9,24 +9,17 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
protected OptionsPage()
|
||||
{
|
||||
//InitializeComponent();
|
||||
Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme;
|
||||
|
||||
Themes.ThemeManager.getInstance().ThemeChanged += ApplyTheme;
|
||||
}
|
||||
|
||||
#region Public Properties
|
||||
[Browsable(false)]public virtual string PageName {get; set;}
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
[Browsable(false)]public virtual string PageName {get; set;}
|
||||
|
||||
public virtual Icon PageIcon {get; set;}
|
||||
public virtual Image IconImage{
|
||||
get
|
||||
{
|
||||
if (PageIcon != null)
|
||||
return PageIcon.ToBitmap();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public virtual Icon PageIcon {get; protected set;}
|
||||
public virtual Image IconImage => PageIcon?.ToBitmap();
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public virtual void ApplyLanguage()
|
||||
@@ -50,26 +43,26 @@ namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
}
|
||||
#endregion
|
||||
|
||||
/*
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// OptionsPage
|
||||
//
|
||||
this.Name = "OptionsPage";
|
||||
this.Size = new System.Drawing.Size(610, 489);
|
||||
this.ResumeLayout(false);
|
||||
Name = "OptionsPage";
|
||||
Size = new Size(610, 489);
|
||||
ResumeLayout(false);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
public virtual void ApplyTheme()
|
||||
protected virtual void ApplyTheme()
|
||||
{
|
||||
if (Themes.ThemeManager.getInstance().ThemingActive)
|
||||
{
|
||||
BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background");
|
||||
ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground");
|
||||
Invalidate();
|
||||
}
|
||||
if (!Themes.ThemeManager.getInstance().ThemingActive) return;
|
||||
BackColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Background");
|
||||
ForeColor = Themes.ThemeManager.getInstance().ActiveTheme.ExtendedPalette.getColor("Dialog_Foreground");
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace mRemoteNG.UI.Forms.OptionsPages
|
||||
{
|
||||
partial class SecurityPage
|
||||
sealed partial class SecurityPage
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user