6
6
using System . Text ;
7
7
using System . Windows . Input ;
8
8
using Windows . Storage . Pickers ;
9
+ using Files . Shared . Helpers ;
9
10
10
11
namespace Files . App . ViewModels . Dialogs
11
12
{
@@ -20,45 +21,151 @@ public sealed class CreateShortcutDialogViewModel : ObservableObject
20
21
// Tells whether destination path exists
21
22
public bool DestinationPathExists { get ; set ; }
22
23
23
- // Tells wheteher the shortcut has been created
24
+ // Tells whether the shortcut has been created
24
25
public bool ShortcutCreatedSuccessfully { get ; private set ; }
25
26
26
27
// Shortcut name with extension
27
28
public string ShortcutCompleteName { get ; private set ; } = string . Empty ;
28
29
29
- // Destination of the shortcut chosen by the user (can be a path or a URL)
30
- private string _destinationItemPath ;
31
- public string DestinationItemPath
30
+ // Full path of the destination item
31
+ public string FullPath { get ; private set ; }
32
+
33
+ // Arguments to be passed to the destination item if it's an executable
34
+ public string Arguments { get ; private set ; }
35
+
36
+ // Previous path of the destination item
37
+ private string _previousShortcutTargetPath ;
38
+
39
+ // Destination of the shortcut chosen by the user (can be a path, a command or a URL)
40
+ private string _shortcutTarget ;
41
+ public string ShortcutTarget
32
42
{
33
- get => _destinationItemPath ;
43
+ get => _shortcutTarget ;
34
44
set
35
45
{
36
- if ( ! SetProperty ( ref _destinationItemPath , value ) )
46
+ if ( ! SetProperty ( ref _shortcutTarget , value ) )
37
47
return ;
38
48
39
49
OnPropertyChanged ( nameof ( ShowWarningTip ) ) ;
40
- if ( string . IsNullOrWhiteSpace ( DestinationItemPath ) )
50
+ if ( string . IsNullOrWhiteSpace ( ShortcutTarget ) )
41
51
{
52
+ DestinationPathExists = false ;
42
53
IsLocationValid = false ;
54
+ _previousShortcutTargetPath = string . Empty ;
43
55
return ;
44
56
}
45
-
46
57
try
47
58
{
48
- DestinationPathExists = Path . Exists ( DestinationItemPath ) && DestinationItemPath != Path . GetPathRoot ( DestinationItemPath ) ;
49
- if ( DestinationPathExists )
59
+ var trimmed = ShortcutTarget . Trim ( ) ;
60
+ // If the text starts with '"', try to parse the quoted part as path, and the rest as arguments
61
+ if ( trimmed . StartsWith ( '"' ) )
50
62
{
51
- IsLocationValid = true ;
63
+ var endQuoteIndex = trimmed . IndexOf ( '"' , 1 ) ;
64
+ if ( endQuoteIndex == - 1 )
65
+ {
66
+ DestinationPathExists = false ;
67
+ IsLocationValid = false ;
68
+ _previousShortcutTargetPath = string . Empty ;
69
+ return ;
70
+ }
71
+
72
+ var quoted = trimmed [ 1 ..endQuoteIndex ] ;
73
+
74
+ if ( quoted == _previousShortcutTargetPath )
75
+ {
76
+ Arguments = ! Directory . Exists ( FullPath ) ? trimmed [ ( endQuoteIndex + 1 ) ..] : string . Empty ;
77
+ return ;
78
+ }
79
+
80
+ if ( IsValidAbsolutePath ( quoted ) )
81
+ {
82
+ DestinationPathExists = true ;
83
+ IsLocationValid = true ;
84
+ FullPath = Path . GetFullPath ( quoted ) ;
85
+ Arguments = ! Directory . Exists ( FullPath ) ? trimmed [ ( endQuoteIndex + 1 ) ..] : string . Empty ;
86
+ _previousShortcutTargetPath = quoted ;
87
+ return ;
88
+ }
89
+
90
+ // If the quoted part is a valid filename, try to find it in the PATH
91
+ if ( quoted == Path . GetFileName ( quoted )
92
+ && quoted . IndexOfAny ( Path . GetInvalidFileNameChars ( ) ) == - 1
93
+ && PathHelpers . TryGetFullPath ( quoted , out var fullPath ) )
94
+ {
95
+ DestinationPathExists = true ;
96
+ IsLocationValid = true ;
97
+ FullPath = fullPath ;
98
+ Arguments = trimmed [ ( endQuoteIndex + 1 ) ..] ;
99
+ _previousShortcutTargetPath = quoted ;
100
+ return ;
101
+ }
102
+
103
+ var uri = new Uri ( quoted ) ;
104
+ DestinationPathExists = false ;
105
+ IsLocationValid = uri . IsWellFormedOriginalString ( ) ;
106
+ FullPath = quoted ;
107
+ Arguments = string . Empty ;
108
+ _previousShortcutTargetPath = string . Empty ;
52
109
}
53
110
else
54
111
{
55
- var uri = new Uri ( DestinationItemPath ) ;
112
+ var filePath = trimmed . Split ( ' ' ) [ 0 ] ;
113
+
114
+ if ( filePath == _previousShortcutTargetPath )
115
+ {
116
+ Arguments = ! Directory . Exists ( FullPath ) ? trimmed . Split ( ' ' ) [ 1 ..] . Aggregate ( string . Empty , ( current , arg ) => current + arg + " " ) : string . Empty ;
117
+ return ;
118
+ }
119
+
120
+ if ( IsValidAbsolutePath ( filePath ) )
121
+ {
122
+ DestinationPathExists = true ;
123
+ IsLocationValid = true ;
124
+ FullPath = Path . GetFullPath ( filePath ) ;
125
+ Arguments = ! Directory . Exists ( FullPath ) ? trimmed . Split ( ' ' ) [ 1 ..] . Aggregate ( string . Empty , ( current , arg ) => current + arg + " " ) : string . Empty ;
126
+ _previousShortcutTargetPath = filePath ;
127
+ return ;
128
+ }
129
+
130
+ // Try to parse the whole text as path
131
+ if ( IsValidAbsolutePath ( trimmed ) )
132
+ {
133
+ DestinationPathExists = true ;
134
+ IsLocationValid = true ;
135
+ FullPath = Path . GetFullPath ( trimmed ) ;
136
+ Arguments = string . Empty ;
137
+ _previousShortcutTargetPath = string . Empty ;
138
+ return ;
139
+ }
140
+
141
+ if ( filePath == Path . GetFileName ( filePath )
142
+ && filePath . IndexOfAny ( Path . GetInvalidFileNameChars ( ) ) == - 1
143
+ && PathHelpers . TryGetFullPath ( filePath , out var fullPath ) )
144
+ {
145
+ DestinationPathExists = true ;
146
+ IsLocationValid = true ;
147
+ FullPath = fullPath ;
148
+ Arguments = trimmed . Split ( ' ' ) [ 1 ..] . Aggregate ( string . Empty , ( current , arg ) => current + arg + " " ) ;
149
+ _previousShortcutTargetPath = filePath ;
150
+ return ;
151
+ }
152
+
153
+ var uri = new Uri ( trimmed ) ;
154
+ DestinationPathExists = false ;
56
155
IsLocationValid = uri . IsWellFormedOriginalString ( ) ;
156
+ FullPath = trimmed ;
157
+ Arguments = string . Empty ;
158
+ _previousShortcutTargetPath = string . Empty ;
57
159
}
160
+
58
161
}
59
162
catch ( Exception )
60
163
{
164
+ DestinationPathExists = false ;
61
165
IsLocationValid = false ;
166
+ FullPath = string . Empty ;
167
+ Arguments = string . Empty ;
168
+ _previousShortcutTargetPath = string . Empty ;
62
169
}
63
170
}
64
171
}
@@ -75,7 +182,7 @@ public bool IsLocationValid
75
182
}
76
183
}
77
184
78
- public bool ShowWarningTip => ! string . IsNullOrEmpty ( DestinationItemPath ) && ! _isLocationValid ;
185
+ public bool ShowWarningTip => ! string . IsNullOrEmpty ( ShortcutTarget ) && ! _isLocationValid ;
79
186
80
187
// Command invoked when the user clicks the 'Browse' button
81
188
public ICommand SelectDestinationCommand { get ; private set ; }
@@ -86,12 +193,17 @@ public bool IsLocationValid
86
193
public CreateShortcutDialogViewModel ( string workingDirectory )
87
194
{
88
195
WorkingDirectory = workingDirectory ;
89
- _destinationItemPath = string . Empty ;
196
+ _shortcutTarget = string . Empty ;
90
197
91
198
SelectDestinationCommand = new AsyncRelayCommand ( SelectDestination ) ;
92
199
PrimaryButtonCommand = new AsyncRelayCommand ( CreateShortcutAsync ) ;
93
200
}
94
201
202
+ private bool IsValidAbsolutePath ( string path )
203
+ {
204
+ return Path . Exists ( path ) && Path . IsPathFullyQualified ( path ) && path != Path . GetPathRoot ( path ) ;
205
+ }
206
+
95
207
private Task SelectDestination ( )
96
208
{
97
209
Win32PInvoke . BROWSEINFO bi = new Win32PInvoke . BROWSEINFO ( ) ;
@@ -103,7 +215,7 @@ private Task SelectDestination()
103
215
StringBuilder path = new StringBuilder ( 260 ) ;
104
216
if ( Win32PInvoke . SHGetPathFromIDList ( pidl , path ) )
105
217
{
106
- DestinationItemPath = path . ToString ( ) ;
218
+ ShortcutTarget = path . ToString ( ) ;
107
219
}
108
220
Marshal . FreeCoTaskMem ( pidl ) ;
109
221
}
@@ -118,10 +230,12 @@ private async Task CreateShortcutAsync()
118
230
119
231
if ( DestinationPathExists )
120
232
{
121
- destinationName = Path . GetFileName ( DestinationItemPath ) ;
122
- if ( string . IsNullOrEmpty ( destinationName ) )
233
+ destinationName = Path . GetFileName ( FullPath ) ;
234
+
235
+ if ( string . IsNullOrEmpty ( FullPath ) )
123
236
{
124
- var destinationPath = DestinationItemPath . Replace ( '/' , '\\ ' ) ;
237
+
238
+ var destinationPath = FullPath . Replace ( '/' , '\\ ' ) ;
125
239
126
240
if ( destinationPath . EndsWith ( '\\ ' ) )
127
241
destinationPath = destinationPath . Substring ( 0 , destinationPath . Length - 1 ) ;
@@ -131,7 +245,7 @@ private async Task CreateShortcutAsync()
131
245
}
132
246
else
133
247
{
134
- var uri = new Uri ( DestinationItemPath ) ;
248
+ var uri = new Uri ( FullPath ) ;
135
249
destinationName = uri . Host ;
136
250
}
137
251
@@ -146,7 +260,7 @@ private async Task CreateShortcutAsync()
146
260
filePath = Path . Combine ( WorkingDirectory , ShortcutCompleteName ) ;
147
261
}
148
262
149
- ShortcutCreatedSuccessfully = await FileOperationsHelpers . CreateOrUpdateLinkAsync ( filePath , DestinationItemPath ) ;
263
+ ShortcutCreatedSuccessfully = await FileOperationsHelpers . CreateOrUpdateLinkAsync ( filePath , FullPath , Arguments ) ;
150
264
}
151
265
}
152
266
}
0 commit comments