Skip to content

Commit 150ce09

Browse files
authored
Merge pull request #851 from Garulf/global-copy-to-clipboard
Global copy to clipboard
2 parents 50e6aad + 8839f1b commit 150ce09

File tree

5 files changed

+75
-0
lines changed

5 files changed

+75
-0
lines changed

Flow.Launcher.Plugin/Result.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ public class Result
2929
/// </summary>
3030
public string ActionKeywordAssigned { get; set; }
3131

32+
/// <summary>
33+
/// This holds the text which can be provided by plugin to be copied to the
34+
/// user's clipboard when Ctrl + C is pressed on a result. If the text is a file/directory path
35+
/// flow will copy the actual file/folder instead of just the path text.
36+
/// </summary>
37+
public string CopyText { get; set; } = string.Empty;
38+
3239
/// <summary>
3340
/// This holds the text which can be provided by plugin to help Flow autocomplete text
3441
/// for user on the plugin result. If autocomplete action for example is tab, pressing tab will have

Flow.Launcher/Languages/en.xaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
<system:String x:Key="copy">Copy</system:String>
1919
<system:String x:Key="cut">Cut</system:String>
2020
<system:String x:Key="paste">Paste</system:String>
21+
<system:String x:Key="fileTitle">File</system:String>
22+
<system:String x:Key="folderTitle">Folder</system:String>
23+
<system:String x:Key="textTitle">Text</system:String>
2124
<system:String x:Key="GameMode">Game Mode</system:String>
2225
<system:String x:Key="GameModeToolTip">Suspend the use of Hotkeys.</system:String>
2326

Flow.Launcher/MainWindow.xaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@
175175
Style="{DynamicResource QueryBoxStyle}"
176176
Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
177177
Visibility="Visible">
178+
<TextBox.CommandBindings>
179+
<CommandBinding Command="ApplicationCommands.Copy" Executed="OnCopy" />
180+
</TextBox.CommandBindings>
178181
<TextBox.ContextMenu>
179182
<ContextMenu>
180183
<MenuItem Command="ApplicationCommands.Cut" Header="{DynamicResource cut}" />

Flow.Launcher/MainWindow.xaml.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,18 @@ public MainWindow()
5252
{
5353
InitializeComponent();
5454
}
55+
private void OnCopy(object sender, ExecutedRoutedEventArgs e)
56+
{
57+
if (QueryTextBox.SelectionLength == 0)
58+
{
59+
_viewModel.ResultCopy(string.Empty);
5560

61+
}
62+
else if (!string.IsNullOrEmpty(QueryTextBox.Text))
63+
{
64+
_viewModel.ResultCopy(QueryTextBox.SelectedText);
65+
}
66+
}
5667
private async void OnClosing(object sender, CancelEventArgs e)
5768
{
5869
_settings.WindowTop = Top;

Flow.Launcher/ViewModel/MainViewModel.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
using Microsoft.VisualStudio.Threading;
2020
using System.Threading.Channels;
2121
using ISavable = Flow.Launcher.Plugin.ISavable;
22+
using System.IO;
23+
using System.Collections.Specialized;
2224

2325
namespace Flow.Launcher.ViewModel
2426
{
@@ -423,6 +425,9 @@ private ResultsViewModel SelectedResults
423425
public ICommand OpenSettingCommand { get; set; }
424426
public ICommand ReloadPluginDataCommand { get; set; }
425427
public ICommand ClearQueryCommand { get; private set; }
428+
429+
public ICommand CopyToClipboard { get; set; }
430+
426431
public ICommand AutocompleteQueryCommand { get; set; }
427432

428433
public string OpenResultCommandModifiers { get; private set; }
@@ -870,6 +875,52 @@ public void UpdateResultView(IEnumerable<ResultsForUpdate> resultsForUpdates)
870875
Results.AddResults(resultsForUpdates, token);
871876
}
872877

878+
/// <summary>
879+
/// This is the global copy method for an individual result. If no text is passed,
880+
/// the method will work out what is to be copied based on the result, so plugin can offer the text
881+
/// to be copied via the result model. If the text is a directory/file path,
882+
/// then actual file/folder will be copied instead.
883+
/// The result's subtitle text is the default text to be copied
884+
/// </summary>
885+
public void ResultCopy(string stringToCopy)
886+
{
887+
if (string.IsNullOrEmpty(stringToCopy))
888+
{
889+
var result = Results.SelectedItem?.Result;
890+
if (result != null)
891+
{
892+
string copyText = string.IsNullOrEmpty(result.CopyText) ? result.SubTitle : result.CopyText;
893+
var isFile = File.Exists(copyText);
894+
var isFolder = Directory.Exists(copyText);
895+
if (isFile || isFolder)
896+
{
897+
var paths = new StringCollection();
898+
paths.Add(copyText);
899+
900+
Clipboard.SetFileDropList(paths);
901+
App.API.ShowMsg(
902+
App.API.GetTranslation("copy")
903+
+" "
904+
+ (isFile? App.API.GetTranslation("fileTitle") : App.API.GetTranslation("folderTitle")),
905+
App.API.GetTranslation("completedSuccessfully"));
906+
}
907+
else
908+
{
909+
Clipboard.SetDataObject(copyText.ToString());
910+
App.API.ShowMsg(
911+
App.API.GetTranslation("copy")
912+
+ " "
913+
+ App.API.GetTranslation("textTitle"),
914+
App.API.GetTranslation("completedSuccessfully"));
915+
}
916+
}
917+
918+
return;
919+
}
920+
921+
Clipboard.SetDataObject(stringToCopy);
922+
}
923+
873924
#endregion
874925
}
875926
}

0 commit comments

Comments
 (0)