From 4daa183dad9cb58b2df56f6ac81a63f7590fa398 Mon Sep 17 00:00:00 2001 From: crschnick Date: Tue, 19 Dec 2023 14:55:50 +0000 Subject: [PATCH] Rework shell terminal command handling and clipboards --- .../xpipe/app/comp/store/StoreEntryComp.java | 13 ++------ .../app/comp/store/StoreSectionComp.java | 13 ++++---- .../io/xpipe/app/ext/DataStoreProvider.java | 2 +- .../app/fxcomps/impl/CodeSnippetComp.java | 9 ++---- .../io/xpipe/app/util/ClipboardHelper.java | 24 +++++++++++++++ .../io/xpipe/core/process/ShellControl.java | 12 +++++--- .../ext/base/action/ShareStoreAction.java | 13 +++----- .../ext/base/browser/CopyPathAction.java | 30 +++++-------------- 8 files changed, 57 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/io/xpipe/app/util/ClipboardHelper.java diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index a3852f54d..45a47bf88 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -28,10 +28,6 @@ import javafx.css.PseudoClass; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; import javafx.scene.control.*; import javafx.scene.input.MouseButton; import javafx.scene.layout.ColumnConstraints; @@ -39,16 +35,13 @@ import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import org.kordamp.ikonli.javafx.FontIcon; -import java.awt.*; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; import java.util.ArrayList; import java.util.Arrays; public abstract class StoreEntryComp extends SimpleComp { public static StoreEntryComp create( - StoreEntryWrapper entry, boolean showIcon, Comp content, boolean preferLarge) { + StoreEntryWrapper entry, Comp content, boolean preferLarge) { if (!preferLarge) { return new DenseStoreEntryComp(entry, true, content); } else { @@ -331,10 +324,8 @@ public abstract class StoreEntryComp extends SimpleComp { l.textProperty().bind(AppI18n.observable("base.copyShareLink")); l.setOnAction(event -> { ThreadHelper.runFailableAsync(() -> { - var selection = new StringSelection(url); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); AppActionLinkDetector.setLastDetectedAction(url); - clipboard.setContents(selection, selection); + ClipboardHelper.copyUrl(url); }); }); menu.getItems().add(l); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java index a77f1347a..ac4ae2ae7 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java @@ -16,6 +16,7 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -108,15 +109,17 @@ public class StoreSectionComp extends Comp> { return; } - struc.get().getStyleClass().removeIf(s -> Arrays.stream(DataStoreColor.values()) + var newList = new ArrayList<>(struc.get().getStyleClass()); + newList.removeIf(s -> Arrays.stream(DataStoreColor.values()) .anyMatch(dataStoreColor -> dataStoreColor.getId().equals(s))); - struc.get().getStyleClass().remove("none"); - struc.get().getStyleClass().add("color-box"); + newList.remove("none"); + newList.add("color-box"); if (val != null) { - struc.get().getStyleClass().add(val.getId()); + newList.add(val.getId()); } else { - struc.get().getStyleClass().add("none"); + newList.add("none"); } + struc.get().getStyleClass().setAll(newList); })) .apply(struc -> { struc.get().pseudoClassStateChanged(ROOT, topLevel); diff --git a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java index f1c283a14..951864dd8 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java @@ -57,7 +57,7 @@ public interface DataStoreProvider { } default Comp customEntryComp(StoreSection s, boolean preferLarge) { - return StoreEntryComp.create(s.getWrapper(),true, null, preferLarge); + return StoreEntryComp.create(s.getWrapper(), null, preferLarge); } default Comp customSectionComp(StoreSection section, boolean topLevel) { diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/CodeSnippetComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/CodeSnippetComp.java index 3e30b0789..2b490e0bc 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/CodeSnippetComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/CodeSnippetComp.java @@ -4,6 +4,7 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; +import io.xpipe.app.util.ClipboardHelper; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableValue; import javafx.scene.control.Button; @@ -14,10 +15,6 @@ import javafx.scene.paint.Color; import org.fxmisc.richtext.InlineCssTextArea; import org.kordamp.ikonli.javafx.FontIcon; -import java.awt.*; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; - public class CodeSnippetComp extends Comp> { private final ObservableValue showLineNumbers; @@ -67,9 +64,7 @@ public class CodeSnippetComp extends Comp> { var button = new Button(); button.setGraphic(new FontIcon("mdoal-content_copy")); button.setOnAction(e -> { - var string = new StringSelection(value.getValue().getRawString()); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(string, string); + ClipboardHelper.copyText(value.getValue().getRawString()); }); button.getStyleClass().add("copy"); button.getStyleClass().add("button-comp"); diff --git a/app/src/main/java/io/xpipe/app/util/ClipboardHelper.java b/app/src/main/java/io/xpipe/app/util/ClipboardHelper.java new file mode 100644 index 000000000..20d72284d --- /dev/null +++ b/app/src/main/java/io/xpipe/app/util/ClipboardHelper.java @@ -0,0 +1,24 @@ +package io.xpipe.app.util; + +import io.xpipe.app.fxcomps.util.PlatformThread; +import javafx.scene.input.Clipboard; +import javafx.scene.input.DataFormat; + +import java.util.Map; + +public class ClipboardHelper { + + public static void copyText(String s) { + PlatformThread.runLaterIfNeeded(() -> { + Clipboard clipboard = Clipboard.getSystemClipboard(); + clipboard.setContent(Map.of(DataFormat.PLAIN_TEXT, s)); + }); + } + + public static void copyUrl(String s) { + PlatformThread.runLaterIfNeeded(() -> { + Clipboard clipboard = Clipboard.getSystemClipboard(); + clipboard.setContent(Map.of(DataFormat.PLAIN_TEXT, s, DataFormat.URL, s)); + }); + } +} diff --git a/core/src/main/java/io/xpipe/core/process/ShellControl.java b/core/src/main/java/io/xpipe/core/process/ShellControl.java index 72b61db57..b82281e5c 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellControl.java @@ -172,22 +172,26 @@ public interface ShellControl extends ProcessControl { FailableSupplier getElevationPassword(); default ShellControl subShell(@NonNull ShellDialect type) { - return subShell(p -> type.getOpenCommand(), (sc, command) -> command != null ? command : type.getLoginOpenCommand()) + return subShell(p -> type.getOpenCommand(), (sc) -> type.getLoginOpenCommand()) .elevationPassword(getElevationPassword()); } interface TerminalOpenFunction { - String prepare(ShellControl sc, String command) throws Exception; + String prepareWithoutInitCommand(ShellControl sc) throws Exception; + + default String prepareWithInitCommand(ShellControl sc, @NonNull String command) throws Exception { + return command; + } } default ShellControl identicalSubShell() { - return subShell(p -> p.getShellDialect().getOpenCommand(), (sc, command) -> command) + return subShell(p -> p.getShellDialect().getOpenCommand(), (sc) -> sc.getShellDialect().getOpenCommand()) .elevationPassword(getElevationPassword()); } default ShellControl subShell(@NonNull String command) { - return subShell(processControl -> command, (sc, command1) -> command1); + return subShell(processControl -> command, (sc) -> command); } default ShellControl enforcedDialect(ShellDialect type) throws Exception { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/ShareStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/ShareStoreAction.java index 3a8648ba1..95270f245 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/ShareStoreAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/ShareStoreAction.java @@ -5,15 +5,12 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.app.util.ClipboardHelper; import io.xpipe.app.util.SecretHelper; import io.xpipe.core.store.DataStore; import javafx.beans.value.ObservableValue; import lombok.Value; -import java.awt.*; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; - public class ShareStoreAction implements ActionProvider { @Value @@ -33,11 +30,9 @@ public class ShareStoreAction implements ActionProvider { @Override public void execute() { - var string = create(store.getStore()); - var selection = new StringSelection(string); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - AppActionLinkDetector.setLastDetectedAction(string); - clipboard.setContents(selection, selection); + var url = create(store.getStore()); + AppActionLinkDetector.setLastDetectedAction(url); + ClipboardHelper.copyUrl(url); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java index a1f4ab537..d78982116 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java @@ -6,15 +6,13 @@ import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.action.BrowserActionFormatter; import io.xpipe.app.browser.action.LeafAction; -import io.xpipe.core.store.FileNames; +import io.xpipe.app.util.ClipboardHelper; import io.xpipe.core.store.FileKind; +import io.xpipe.core.store.FileNames; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; -import java.awt.*; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; import java.util.List; import java.util.stream.Collectors; @@ -60,9 +58,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { var s = entries.stream() .map(entry -> entry.getRawFileEntry().getPath()) .collect(Collectors.joining("\n")); - var selection = new StringSelection(s); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); + ClipboardHelper.copyText(s); } }, new LeafAction() { @@ -94,9 +90,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { var s = entries.stream() .map(entry -> entry.getRawFileEntry().getPath()) .collect(Collectors.joining("\n")); - var selection = new StringSelection(s); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); + ClipboardHelper.copyText(s); } }, new LeafAction() { @@ -124,9 +118,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { var s = entries.stream() .map(entry -> "\"" + entry.getRawFileEntry().getPath() + "\"") .collect(Collectors.joining("\n")); - var selection = new StringSelection(s); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); + ClipboardHelper.copyText(s); } }, new LeafAction() { @@ -156,9 +148,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { .map(entry -> FileNames.getFileName( entry.getRawFileEntry().getPath())) .collect(Collectors.joining("\n")); - var selection = new StringSelection(s); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); + ClipboardHelper.copyText(s); } }, new LeafAction() { @@ -200,9 +190,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { .map(entry -> FileNames.getFileName( entry.getRawFileEntry().getPath())) .collect(Collectors.joining("\n")); - var selection = new StringSelection(s); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); + ClipboardHelper.copyText(s); } }, new LeafAction() { @@ -235,9 +223,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { + FileNames.getFileName( entry.getRawFileEntry().getPath()) + "\"") .collect(Collectors.joining("\n")); - var selection = new StringSelection(s); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); + ClipboardHelper.copyText(s); } }); }