mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +00:00
Reformat and fr translations
This commit is contained in:
parent
cd485525b3
commit
ea0e34dab4
145 changed files with 2294 additions and 973 deletions
|
@ -12,9 +12,11 @@ public class Main {
|
|||
return;
|
||||
}
|
||||
|
||||
// Since this is not marked as a console application, it will not print anything when you run it in a console on Windows
|
||||
// Since this is not marked as a console application, it will not print anything when you run it in a console on
|
||||
// Windows
|
||||
if (args.length == 1 && args[0].equals("--help")) {
|
||||
System.out.println("""
|
||||
System.out.println(
|
||||
"""
|
||||
The daemon executable xpiped does not accept any command-line arguments.
|
||||
|
||||
For a reference on what you can do from the CLI, take a look at the xpipe CLI executable instead.
|
||||
|
|
|
@ -39,8 +39,7 @@ public final class BrowserBookmarkComp extends SimpleComp {
|
|||
public BrowserBookmarkComp(
|
||||
ObservableValue<DataStoreEntry> selected,
|
||||
Predicate<StoreEntryWrapper> applicable,
|
||||
BiConsumer<StoreEntryWrapper, BooleanProperty> action
|
||||
) {
|
||||
BiConsumer<StoreEntryWrapper, BooleanProperty> action) {
|
||||
this.selected = selected;
|
||||
this.applicable = applicable;
|
||||
this.action = action;
|
||||
|
@ -66,8 +65,8 @@ public final class BrowserBookmarkComp extends SimpleComp {
|
|||
.pseudoClassStateChanged(
|
||||
SELECTED,
|
||||
newValue != null
|
||||
&& newValue
|
||||
.equals(s.getWrapper().getEntry()));
|
||||
&& newValue.equals(
|
||||
s.getWrapper().getEntry()));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,7 +40,7 @@ public class BrowserBreadcrumbBar extends SimpleComp {
|
|||
|
||||
var breadcrumbs = new Breadcrumbs<String>();
|
||||
breadcrumbs.setMinWidth(0);
|
||||
PlatformThread.sync(model.getCurrentPath()).subscribe( val -> {
|
||||
PlatformThread.sync(model.getCurrentPath()).subscribe(val -> {
|
||||
if (val == null) {
|
||||
breadcrumbs.setSelectedCrumb(null);
|
||||
return;
|
||||
|
|
|
@ -4,8 +4,8 @@ import atlantafx.base.theme.Styles;
|
|||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.impl.TooltipAugment;
|
||||
import io.xpipe.app.fxcomps.impl.TextFieldComp;
|
||||
import io.xpipe.app.fxcomps.impl.TooltipAugment;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.geometry.Pos;
|
||||
|
|
|
@ -128,6 +128,10 @@ public class BrowserStatusBarComp extends SimpleComp {
|
|||
});
|
||||
|
||||
// Use status bar as an extension of file list
|
||||
new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, null, () -> new BrowserContextMenu(model, null)).augment(new SimpleCompStructure<>(r));
|
||||
new ContextMenuAugment<>(
|
||||
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY,
|
||||
null,
|
||||
() -> new BrowserContextMenu(model, null))
|
||||
.augment(new SimpleCompStructure<>(r));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,14 +123,15 @@ public class BrowserTransferComp extends SimpleComp {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!(model.getBrowserSessionModel().getSelectedEntry().getValue() instanceof OpenFileSystemModel fileSystemModel)) {
|
||||
if (!(model.getBrowserSessionModel()
|
||||
.getSelectedEntry()
|
||||
.getValue()
|
||||
instanceof OpenFileSystemModel fileSystemModel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var files = drag.getEntries();
|
||||
model.drop(
|
||||
fileSystemModel,
|
||||
files);
|
||||
model.drop(fileSystemModel, files);
|
||||
event.setDropCompleted(true);
|
||||
event.consume();
|
||||
}
|
||||
|
|
|
@ -78,15 +78,14 @@ public class BrowserWelcomeComp extends SimpleComp {
|
|||
});
|
||||
var empty = Bindings.createBooleanBinding(() -> list.isEmpty(), list);
|
||||
|
||||
var headerBinding = BindingsHelper.flatMap(empty,b -> {
|
||||
var headerBinding = BindingsHelper.flatMap(empty, b -> {
|
||||
if (b) {
|
||||
return AppI18n.observable("browserWelcomeEmpty");
|
||||
} else {
|
||||
return AppI18n.observable("browserWelcomeSystems");
|
||||
}
|
||||
});
|
||||
var header = new LabelComp(headerBinding)
|
||||
.createRegion();
|
||||
var header = new LabelComp(headerBinding).createRegion();
|
||||
AppFont.setSize(header, 1);
|
||||
vbox.getChildren().add(header);
|
||||
|
||||
|
@ -130,11 +129,13 @@ public class BrowserWelcomeComp extends SimpleComp {
|
|||
|
||||
private Comp<?> entryButton(BrowserSavedState.Entry e, BooleanProperty disable) {
|
||||
var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid());
|
||||
var graphic = entry.get()
|
||||
.getProvider()
|
||||
.getDisplayIconFileName(entry.get().getStore());
|
||||
var graphic =
|
||||
entry.get().getProvider().getDisplayIconFileName(entry.get().getStore());
|
||||
var view = PrettyImageHelper.ofFixedSize(graphic, 30, 24);
|
||||
return new ButtonComp(new SimpleStringProperty(DataStorage.get().getStoreDisplayName(entry.get())), view.createRegion(), () -> {
|
||||
return new ButtonComp(
|
||||
new SimpleStringProperty(DataStorage.get().getStoreDisplayName(entry.get())),
|
||||
view.createRegion(),
|
||||
() -> {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
model.restoreStateAsync(e, disable);
|
||||
});
|
||||
|
|
|
@ -92,6 +92,5 @@ public interface BrowserAction {
|
|||
})
|
||||
.toList());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,7 @@ public interface LeafAction extends BrowserAction {
|
|||
return b;
|
||||
}
|
||||
|
||||
default MenuItem toMenuItem(
|
||||
OpenFileSystemModel model, List<BrowserEntry> selected) {
|
||||
default MenuItem toMenuItem(OpenFileSystemModel model, List<BrowserEntry> selected) {
|
||||
var name = getName(model, selected);
|
||||
var mi = new MenuItem();
|
||||
mi.textProperty().bind(name);
|
||||
|
|
|
@ -43,7 +43,9 @@ public abstract class MultiExecuteAction implements BranchAction {
|
|||
@Override
|
||||
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
var t = AppPrefs.get().terminalType().getValue();
|
||||
return AppI18n.observable("executeInTerminal", t != null ? t.toTranslatedString().getValue() : "?");
|
||||
return AppI18n.observable(
|
||||
"executeInTerminal",
|
||||
t != null ? t.toTranslatedString().getValue() : "?");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.app.browser.file;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserFileListModel;
|
||||
import io.xpipe.app.browser.icon.BrowserIconDirectoryType;
|
||||
import io.xpipe.app.browser.icon.BrowserIconFileType;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
|
|
@ -507,13 +507,18 @@ public final class BrowserFileListComp extends SimpleComp {
|
|||
.hide(Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
var item = getTableRow().getItem();
|
||||
var notDir = item.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY;
|
||||
var isParentLink = item
|
||||
.getRawFileEntry()
|
||||
.equals(fileList.getFileSystemModel().getCurrentParentDirectory());
|
||||
var notDir = item.getRawFileEntry()
|
||||
.resolved()
|
||||
.getKind()
|
||||
!= FileKind.DIRECTORY;
|
||||
var isParentLink = item.getRawFileEntry()
|
||||
.equals(fileList.getFileSystemModel()
|
||||
.getCurrentParentDirectory());
|
||||
return notDir || isParentLink;
|
||||
},
|
||||
itemProperty()).not().not())
|
||||
itemProperty())
|
||||
.not()
|
||||
.not())
|
||||
.createRegion();
|
||||
|
||||
editing.addListener((observable, oldValue, newValue) -> {
|
||||
|
|
|
@ -32,8 +32,10 @@ public class BrowserFileOverviewComp extends SimpleComp {
|
|||
Function<FileSystem.FileEntry, Comp<?>> factory = entry -> {
|
||||
return Comp.of(() -> {
|
||||
var icon = BrowserIcons.createIcon(entry);
|
||||
var graphic = new HorizontalComp(List.of(icon,
|
||||
new BrowserQuickAccessButtonComp(() -> new BrowserEntry(entry, model.getFileList(),false),model)));
|
||||
var graphic = new HorizontalComp(List.of(
|
||||
icon,
|
||||
new BrowserQuickAccessButtonComp(
|
||||
() -> new BrowserEntry(entry, model.getFileList(), false), model)));
|
||||
var l = new Button(entry.getPath(), graphic.createRegion());
|
||||
l.setGraphicTextGap(1);
|
||||
l.setOnAction(event -> {
|
||||
|
|
|
@ -29,18 +29,105 @@ import java.util.stream.Collectors;
|
|||
|
||||
public class BrowserQuickAccessContextMenu extends ContextMenu {
|
||||
|
||||
private final Supplier<BrowserEntry> base;
|
||||
private final OpenFileSystemModel model;
|
||||
private ContextMenu shownBrowserActionsMenu;
|
||||
private boolean expandBrowserActionMenuKey;
|
||||
private boolean keyBasedNavigation;
|
||||
private boolean closeBrowserActionMenuKey;
|
||||
public BrowserQuickAccessContextMenu(Supplier<BrowserEntry> base, OpenFileSystemModel model) {
|
||||
this.base = base;
|
||||
this.model = model;
|
||||
|
||||
addEventFilter(Menu.ON_SHOWING, e -> {
|
||||
Node content = getSkin().getNode();
|
||||
if (content instanceof Region r) {
|
||||
r.setMaxWidth(500);
|
||||
}
|
||||
});
|
||||
addEventFilter(Menu.ON_SHOWN, e -> {
|
||||
Platform.runLater(() -> {
|
||||
getItems().getFirst().getStyleableNode().requestFocus();
|
||||
});
|
||||
});
|
||||
InputHelper.onLeft(this, false, e -> {
|
||||
hide();
|
||||
e.consume();
|
||||
});
|
||||
setAutoHide(true);
|
||||
getStyleClass().add("condensed");
|
||||
}
|
||||
|
||||
public void showMenu(Node anchor) {
|
||||
getItems().clear();
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
var entry = base.get();
|
||||
if (entry.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY) {
|
||||
return;
|
||||
}
|
||||
|
||||
var actionsMenu = new AtomicReference<ContextMenu>();
|
||||
var r = new Menu();
|
||||
var newItems = updateMenuItems(r, entry, true);
|
||||
Platform.runLater(() -> {
|
||||
getItems().addAll(r.getItems());
|
||||
show(anchor, Side.RIGHT, 0, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private MenuItem createItem(BrowserEntry browserEntry) {
|
||||
return new QuickAccessMenu(browserEntry).getMenu();
|
||||
}
|
||||
|
||||
private List<MenuItem> updateMenuItems(Menu m, BrowserEntry entry, boolean updateInstantly) throws Exception {
|
||||
var newFiles = model.getFileSystem()
|
||||
.listFiles(entry.getRawFileEntry().resolved().getPath());
|
||||
try (var s = newFiles) {
|
||||
var list = s.map(fileEntry -> fileEntry.resolved()).toList();
|
||||
// Wait until all files are listed, i.e. do not skip the stream elements
|
||||
list = list.subList(0, Math.min(list.size(), 150));
|
||||
|
||||
var newItems = new ArrayList<MenuItem>();
|
||||
if (list.isEmpty()) {
|
||||
var empty = new Menu("<empty>");
|
||||
empty.getStyleClass().add("leaf");
|
||||
newItems.add(empty);
|
||||
} else {
|
||||
var browserEntries = list.stream()
|
||||
.map(fileEntry -> new BrowserEntry(fileEntry, model.getFileList(), false))
|
||||
.toList();
|
||||
var menus = browserEntries.stream()
|
||||
.sorted(model.getFileList().order())
|
||||
.collect(Collectors.toMap(e -> e, e -> createItem(e), (v1, v2) -> v2, LinkedHashMap::new));
|
||||
var dirs = browserEntries.stream()
|
||||
.filter(e -> e.getRawFileEntry().getKind() == FileKind.DIRECTORY)
|
||||
.toList();
|
||||
if (dirs.size() == 1) {
|
||||
updateMenuItems((Menu) menus.get(dirs.getFirst()), dirs.getFirst(), true);
|
||||
}
|
||||
newItems.addAll(menus.values());
|
||||
}
|
||||
if (updateInstantly) {
|
||||
m.getItems().setAll(newItems);
|
||||
}
|
||||
return newItems;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
class QuickAccessMenu {
|
||||
private final BrowserEntry browserEntry;
|
||||
private ContextMenu browserActionMenu;
|
||||
private final Menu menu;
|
||||
private ContextMenu browserActionMenu;
|
||||
|
||||
public QuickAccessMenu(BrowserEntry browserEntry) {
|
||||
this.browserEntry = browserEntry;
|
||||
this.menu = new Menu(
|
||||
// Use original name, not the link target
|
||||
browserEntry.getRawFileEntry().getName(),
|
||||
PrettyImageHelper.ofFixedSizeSquare(FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24)
|
||||
PrettyImageHelper.ofFixedSizeSquare(
|
||||
FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24)
|
||||
.createRegion());
|
||||
createMenu();
|
||||
addInputListeners();
|
||||
|
@ -142,7 +229,8 @@ public class BrowserQuickAccessContextMenu extends ContextMenu {
|
|||
});
|
||||
new BooleanAnimationTimer(hover, 100, () -> {
|
||||
expandDirectoryMenu(empty);
|
||||
}).start();
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
private void addInputListeners() {
|
||||
|
@ -155,13 +243,15 @@ public class BrowserQuickAccessContextMenu extends ContextMenu {
|
|||
} else {
|
||||
expandBrowserActionMenuKey = false;
|
||||
}
|
||||
if (event.getCode().equals(KeyCode.LEFT) && browserActionMenu != null && browserActionMenu.isShowing()) {
|
||||
if (event.getCode().equals(KeyCode.LEFT)
|
||||
&& browserActionMenu != null
|
||||
&& browserActionMenu.isShowing()) {
|
||||
closeBrowserActionMenuKey = true;
|
||||
} else {
|
||||
closeBrowserActionMenuKey = false;
|
||||
}
|
||||
});
|
||||
contextMenu.addEventFilter(MouseEvent.ANY,event -> {
|
||||
contextMenu.addEventFilter(MouseEvent.ANY, event -> {
|
||||
keyBasedNavigation = false;
|
||||
});
|
||||
}
|
||||
|
@ -217,102 +307,4 @@ public class BrowserQuickAccessContextMenu extends ContextMenu {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
private final Supplier<BrowserEntry> base;
|
||||
private final OpenFileSystemModel model;
|
||||
private ContextMenu shownBrowserActionsMenu;
|
||||
|
||||
private boolean expandBrowserActionMenuKey;
|
||||
private boolean keyBasedNavigation;
|
||||
private boolean closeBrowserActionMenuKey;
|
||||
|
||||
public BrowserQuickAccessContextMenu(Supplier<BrowserEntry> base, OpenFileSystemModel model) {
|
||||
this.base = base;
|
||||
this.model = model;
|
||||
|
||||
addEventFilter(Menu.ON_SHOWING, e -> {
|
||||
Node content = getSkin().getNode();
|
||||
if (content instanceof Region r) {
|
||||
r.setMaxWidth(500);
|
||||
}
|
||||
});
|
||||
addEventFilter(Menu.ON_SHOWN, e -> {
|
||||
Platform.runLater(() -> {
|
||||
getItems().getFirst().getStyleableNode().requestFocus();
|
||||
});
|
||||
});
|
||||
InputHelper.onLeft(this, false, e -> {
|
||||
hide();
|
||||
e.consume();
|
||||
});
|
||||
setAutoHide(true);
|
||||
getStyleClass().add("condensed");
|
||||
}
|
||||
|
||||
public void showMenu(Node anchor) {
|
||||
getItems().clear();
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
var entry = base.get();
|
||||
if (entry.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY) {
|
||||
return;
|
||||
}
|
||||
|
||||
var actionsMenu = new AtomicReference<ContextMenu>();
|
||||
var r = new Menu();
|
||||
var newItems = updateMenuItems(r, entry, true);
|
||||
Platform.runLater(() -> {
|
||||
getItems().addAll(r.getItems());
|
||||
show(anchor, Side.RIGHT, 0, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private MenuItem createItem(BrowserEntry browserEntry) {
|
||||
return new QuickAccessMenu(browserEntry).getMenu();
|
||||
}
|
||||
|
||||
private List<MenuItem> updateMenuItems(
|
||||
Menu m,
|
||||
BrowserEntry entry,
|
||||
boolean updateInstantly)
|
||||
throws Exception {
|
||||
var newFiles = model.getFileSystem().listFiles(entry.getRawFileEntry().resolved().getPath());
|
||||
try (var s = newFiles) {
|
||||
var list = s.map(fileEntry -> fileEntry.resolved()).toList();
|
||||
// Wait until all files are listed, i.e. do not skip the stream elements
|
||||
list = list.subList(0, Math.min(list.size(), 150));
|
||||
|
||||
var newItems = new ArrayList<MenuItem>();
|
||||
if (list.isEmpty()) {
|
||||
var empty = new Menu("<empty>");
|
||||
empty.getStyleClass().add("leaf");
|
||||
newItems.add(empty);
|
||||
} else {
|
||||
var browserEntries = list.stream()
|
||||
.map(fileEntry -> new BrowserEntry(fileEntry, model.getFileList(), false))
|
||||
.toList();
|
||||
var menus = browserEntries.stream()
|
||||
.sorted(model.getFileList().order())
|
||||
.collect(Collectors.toMap(
|
||||
e -> e,
|
||||
e -> createItem(e),
|
||||
(v1, v2) -> v2,
|
||||
LinkedHashMap::new));
|
||||
var dirs = browserEntries.stream()
|
||||
.filter(e -> e.getRawFileEntry().getKind() == FileKind.DIRECTORY)
|
||||
.toList();
|
||||
if (dirs.size() == 1) {
|
||||
updateMenuItems(
|
||||
(Menu) menus.get(dirs.getFirst()),
|
||||
dirs.getFirst(),
|
||||
true);
|
||||
}
|
||||
newItems.addAll(menus.values());
|
||||
}
|
||||
if (updateInstantly) {
|
||||
m.getItems().setAll(newItems);
|
||||
}
|
||||
return newItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,8 +296,11 @@ public class FileSystemHelper {
|
|||
AtomicLong transferred = new AtomicLong();
|
||||
for (var e : flatFiles.entrySet()) {
|
||||
var sourceFile = e.getKey();
|
||||
var targetFile = target.getFileSystem().getShell().orElseThrow().getOsType().makeFileSystemCompatible(
|
||||
FileNames.join(target.getPath(), e.getValue()));
|
||||
var targetFile = target.getFileSystem()
|
||||
.getShell()
|
||||
.orElseThrow()
|
||||
.getOsType()
|
||||
.makeFileSystemCompatible(FileNames.join(target.getPath(), e.getValue()));
|
||||
if (sourceFile.getFileSystem().equals(target.getFileSystem())) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
|
|
@ -60,7 +60,9 @@ public class OpenFileSystemComp extends SimpleComp {
|
|||
|
||||
var menuButton = new MenuButton(null, new FontIcon("mdral-folder_open"));
|
||||
new ContextMenuAugment<>(
|
||||
event -> event.getButton() == MouseButton.PRIMARY, null, () -> new BrowserContextMenu(model, null))
|
||||
event -> event.getButton() == MouseButton.PRIMARY,
|
||||
null,
|
||||
() -> new BrowserContextMenu(model, null))
|
||||
.augment(new SimpleCompStructure<>(menuButton));
|
||||
menuButton.disableProperty().bind(model.getInOverview());
|
||||
menuButton.setAccessibleText("Directory options");
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.xpipe.app.browser.fs;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserFileListModel;
|
||||
import io.xpipe.app.browser.BrowserSavedState;
|
||||
import io.xpipe.app.browser.BrowserTransferProgress;
|
||||
import io.xpipe.app.browser.file.FileSystemHelper;
|
||||
import io.xpipe.app.browser.action.BrowserAction;
|
||||
import io.xpipe.app.browser.file.BrowserFileListModel;
|
||||
import io.xpipe.app.browser.file.FileSystemHelper;
|
||||
import io.xpipe.app.browser.session.BrowserAbstractSessionModel;
|
||||
import io.xpipe.app.browser.session.BrowserSessionModel;
|
||||
import io.xpipe.app.browser.session.BrowserSessionTab;
|
||||
|
@ -49,7 +49,10 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
private OpenFileSystemSavedState savedState;
|
||||
private OpenFileSystemCache cache;
|
||||
|
||||
public OpenFileSystemModel(BrowserAbstractSessionModel<?> model, DataStoreEntryRef<? extends FileSystemStore> entry, SelectionMode selectionMode) {
|
||||
public OpenFileSystemModel(
|
||||
BrowserAbstractSessionModel<?> model,
|
||||
DataStoreEntryRef<? extends FileSystemStore> entry,
|
||||
SelectionMode selectionMode) {
|
||||
super(model, entry);
|
||||
this.inOverview.bind(Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
|
@ -103,7 +106,9 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
&& savedState != null
|
||||
&& getCurrentPath().get() != null) {
|
||||
if (getBrowserModel() instanceof BrowserSessionModel bm) {
|
||||
bm.getSavedState().add(new BrowserSavedState.Entry(getEntry().get().getUuid(), getCurrentPath().get()));
|
||||
bm.getSavedState()
|
||||
.add(new BrowserSavedState.Entry(
|
||||
getEntry().get().getUuid(), getCurrentPath().get()));
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
@ -114,7 +119,6 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
|
|||
fileSystem = null;
|
||||
}
|
||||
|
||||
|
||||
private void startIfNeeded() throws Exception {
|
||||
if (fileSystem == null) {
|
||||
return;
|
||||
|
|
|
@ -19,14 +19,14 @@ public abstract class BrowserIconDirectoryType {
|
|||
|
||||
private static final List<BrowserIconDirectoryType> ALL = new ArrayList<>();
|
||||
|
||||
public synchronized static BrowserIconDirectoryType byId(String id) {
|
||||
public static synchronized BrowserIconDirectoryType byId(String id) {
|
||||
return ALL.stream()
|
||||
.filter(fileType -> fileType.getId().equals(id))
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
public synchronized static void loadDefinitions() {
|
||||
public static synchronized void loadDefinitions() {
|
||||
ALL.add(new BrowserIconDirectoryType() {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,14 +16,14 @@ public abstract class BrowserIconFileType {
|
|||
|
||||
private static final List<BrowserIconFileType> ALL = new ArrayList<>();
|
||||
|
||||
public synchronized static BrowserIconFileType byId(String id) {
|
||||
public static synchronized BrowserIconFileType byId(String id) {
|
||||
return ALL.stream()
|
||||
.filter(fileType -> fileType.getId().equals(id))
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
public synchronized static void loadDefinitions() {
|
||||
public static synchronized void loadDefinitions() {
|
||||
AppResources.with(AppResources.XPIPE_MODULE, "file_list.txt", path -> {
|
||||
try (var reader =
|
||||
new BufferedReader(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))) {
|
||||
|
|
|
@ -50,7 +50,8 @@ public class BrowserChooserComp extends SimpleComp {
|
|||
var comp = new BrowserChooserComp(model)
|
||||
.apply(struc -> struc.get().setPrefSize(1200, 700))
|
||||
.apply(struc -> AppFont.normal(struc.get()));
|
||||
var window = AppWindowHelper.sideWindow(AppI18n.get(save ? "saveFileTitle" : "openFileTitle"), stage -> comp, false, null);
|
||||
var window = AppWindowHelper.sideWindow(
|
||||
AppI18n.get(save ? "saveFileTitle" : "openFileTitle"), stage -> comp, false, null);
|
||||
model.setOnFinish(fileStores -> {
|
||||
file.accept(fileStores.size() > 0 ? fileStores.getFirst() : null);
|
||||
window.close();
|
||||
|
@ -81,7 +82,12 @@ public class BrowserChooserComp extends SimpleComp {
|
|||
});
|
||||
};
|
||||
|
||||
var bookmarksList = new BrowserBookmarkComp(BindingsHelper.map(model.getSelectedEntry(), v -> v.getEntry().get()), applicable, action).vgrow();
|
||||
var bookmarksList = new BrowserBookmarkComp(
|
||||
BindingsHelper.map(
|
||||
model.getSelectedEntry(), v -> v.getEntry().get()),
|
||||
applicable,
|
||||
action)
|
||||
.vgrow();
|
||||
var stack = Comp.of(() -> {
|
||||
var s = new StackPane();
|
||||
model.getSelectedEntry().subscribe(selected -> {
|
||||
|
|
|
@ -103,5 +103,4 @@ public class BrowserChooserModel extends BrowserAbstractSessionModel<OpenFileSys
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,7 +46,12 @@ public class BrowserSessionComp extends SimpleComp {
|
|||
});
|
||||
};
|
||||
|
||||
var bookmarksList = new BrowserBookmarkComp(BindingsHelper.map(model.getSelectedEntry(), v -> v.getEntry().get()), applicable, action).vgrow();
|
||||
var bookmarksList = new BrowserBookmarkComp(
|
||||
BindingsHelper.map(
|
||||
model.getSelectedEntry(), v -> v.getEntry().get()),
|
||||
applicable,
|
||||
action)
|
||||
.vgrow();
|
||||
var localDownloadStage = new BrowserTransferComp(model.getLocalTransfersStage())
|
||||
.hide(PlatformThread.sync(Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
|
|
|
@ -28,7 +28,6 @@ public class BrowserSessionModel extends BrowserAbstractSessionModel<BrowserSess
|
|||
private final BrowserTransferModel localTransfersStage = new BrowserTransferModel(this);
|
||||
private final BrowserSavedState savedState;
|
||||
|
||||
|
||||
public BrowserSessionModel(BrowserSavedState savedState) {
|
||||
this.savedState = savedState;
|
||||
}
|
||||
|
|
|
@ -38,11 +38,7 @@ public class BrowserSessionMultiTab extends BrowserSessionTab<DataStore> {
|
|||
return true;
|
||||
}
|
||||
|
||||
public void init() throws Exception {
|
||||
public void init() throws Exception {}
|
||||
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
}
|
||||
public void close() {}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,8 @@ public class BrowserSessionTabsComp extends SimpleComp {
|
|||
tabs.getTabs().add(t);
|
||||
});
|
||||
tabs.getSelectionModel()
|
||||
.select(model.getSessionEntries().indexOf(model.getSelectedEntry().getValue()));
|
||||
.select(model.getSessionEntries()
|
||||
.indexOf(model.getSelectedEntry().getValue()));
|
||||
|
||||
// Used for ignoring changes by the tabpane when new tabs are added. We want to perform the selections manually!
|
||||
var modifying = new SimpleBooleanProperty();
|
||||
|
|
|
@ -24,9 +24,14 @@ public class AppLayoutComp extends Comp<CompStructure<Pane>> {
|
|||
|
||||
@Override
|
||||
public CompStructure<Pane> createBase() {
|
||||
Map<Comp<?>, ObservableValue<Boolean>> map = model.getEntries().stream().collect(Collectors.toMap(entry -> entry.comp(), entry -> Bindings.createBooleanBinding(() -> {
|
||||
Map<Comp<?>, ObservableValue<Boolean>> map = model.getEntries().stream()
|
||||
.collect(Collectors.toMap(
|
||||
entry -> entry.comp(),
|
||||
entry -> Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
return model.getSelected().getValue().equals(entry);
|
||||
}, model.getSelected())));
|
||||
},
|
||||
model.getSelected())));
|
||||
var multi = new MultiContentComp(map);
|
||||
|
||||
var pane = new BorderPane();
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.xpipe.app.comp.base;
|
|||
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
@ -12,19 +11,7 @@ import lombok.Value;
|
|||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class FontIconComp extends Comp <FontIconComp.Structure>{
|
||||
|
||||
@Value
|
||||
public static class Structure implements CompStructure<StackPane> {
|
||||
|
||||
FontIcon icon;
|
||||
StackPane pane;
|
||||
|
||||
@Override
|
||||
public StackPane get() {
|
||||
return pane;
|
||||
}
|
||||
}
|
||||
public class FontIconComp extends Comp<FontIconComp.Structure> {
|
||||
|
||||
private final ObservableValue<String> icon;
|
||||
|
||||
|
@ -45,4 +32,16 @@ public class FontIconComp extends Comp <FontIconComp.Structure>{
|
|||
var pane = new StackPane(fi);
|
||||
return new FontIconComp.Structure(fi, pane);
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class Structure implements CompStructure<StackPane> {
|
||||
|
||||
FontIcon icon;
|
||||
StackPane pane;
|
||||
|
||||
@Override
|
||||
public StackPane get() {
|
||||
return pane;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,9 +53,8 @@ public class OsLogoComp extends SimpleComp {
|
|||
wrapper.getPersistentState(),
|
||||
state);
|
||||
var hide = BindingsHelper.map(img, s -> s != null);
|
||||
return new StackComp(List.of(
|
||||
new SystemStateComp(state).hide(hide),
|
||||
new PrettyImageComp(img, 24, 24).visible(hide)))
|
||||
return new StackComp(
|
||||
List.of(new SystemStateComp(state).hide(hide), new PrettyImageComp(img, 24, 24).visible(hide)))
|
||||
.createRegion();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ import io.xpipe.app.fxcomps.Comp;
|
|||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
import io.xpipe.app.fxcomps.augment.Augment;
|
||||
import io.xpipe.app.fxcomps.impl.TooltipAugment;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import io.xpipe.app.fxcomps.impl.TooltipAugment;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.UserReportComp;
|
||||
|
|
|
@ -22,7 +22,7 @@ public class ToggleSwitchComp extends SimpleComp {
|
|||
@Override
|
||||
protected Region createSimple() {
|
||||
var s = new ToggleSwitch();
|
||||
s.addEventFilter(KeyEvent.KEY_PRESSED,event -> {
|
||||
s.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (event.getCode() == KeyCode.SPACE || event.getCode() == KeyCode.ENTER) {
|
||||
s.setSelected(!s.isSelected());
|
||||
event.consume();
|
||||
|
|
|
@ -95,7 +95,11 @@ public abstract class StoreEntryComp extends SimpleComp {
|
|||
wrapper.executeDefaultAction();
|
||||
});
|
||||
});
|
||||
new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, null, () -> this.createContextMenu()).augment(button);
|
||||
new ContextMenuAugment<>(
|
||||
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY,
|
||||
null,
|
||||
() -> this.createContextMenu())
|
||||
.augment(button);
|
||||
|
||||
var loading = LoadingOverlayComp.noProgress(
|
||||
Comp.of(() -> button),
|
||||
|
@ -244,7 +248,9 @@ public abstract class StoreEntryComp extends SimpleComp {
|
|||
settingsButton.styleClass("settings");
|
||||
settingsButton.accessibleText("More");
|
||||
settingsButton.apply(new ContextMenuAugment<>(
|
||||
event -> event.getButton() == MouseButton.PRIMARY, null, () -> StoreEntryComp.this.createContextMenu()));
|
||||
event -> event.getButton() == MouseButton.PRIMARY,
|
||||
null,
|
||||
() -> StoreEntryComp.this.createContextMenu()));
|
||||
settingsButton.apply(new TooltipAugment<>("more"));
|
||||
return settingsButton;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ import io.xpipe.app.core.AppFont;
|
|||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.TooltipAugment;
|
||||
import io.xpipe.app.fxcomps.impl.FilterComp;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import io.xpipe.app.fxcomps.impl.TooltipAugment;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.ListBindingsHelper;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
|
@ -51,8 +51,12 @@ public class StoreEntryListStatusComp extends SimpleComp {
|
|||
|
||||
private Region createGroupListHeader() {
|
||||
var label = new Label();
|
||||
var name = BindingsHelper.flatMap(StoreViewState.get().getActiveCategory(),
|
||||
categoryWrapper -> AppI18n.observable(categoryWrapper.getRoot().equals(StoreViewState.get().getAllConnectionsCategory()) ? "connections" : "scripts"));
|
||||
var name = BindingsHelper.flatMap(
|
||||
StoreViewState.get().getActiveCategory(),
|
||||
categoryWrapper -> AppI18n.observable(
|
||||
categoryWrapper.getRoot().equals(StoreViewState.get().getAllConnectionsCategory())
|
||||
? "connections"
|
||||
: "scripts"));
|
||||
label.textProperty().bind(name);
|
||||
label.getStyleClass().add("name");
|
||||
|
||||
|
|
|
@ -46,9 +46,7 @@ public class StoreIntroComp extends SimpleComp {
|
|||
hbox.setSpacing(35);
|
||||
hbox.setAlignment(Pos.CENTER);
|
||||
|
||||
var v = new VBox(
|
||||
hbox, scanPane
|
||||
);
|
||||
var v = new VBox(hbox, scanPane);
|
||||
v.setMinWidth(Region.USE_PREF_SIZE);
|
||||
v.setMaxWidth(Region.USE_PREF_SIZE);
|
||||
v.setMinHeight(Region.USE_PREF_SIZE);
|
||||
|
|
|
@ -42,7 +42,9 @@ public class StoreQuickAccessButtonComp extends Comp<CompStructure<Button>> {
|
|||
var graphic =
|
||||
w.getEntry().getProvider().getDisplayIconFileName(w.getEntry().getStore());
|
||||
if (c.isEmpty()) {
|
||||
var item = ContextMenuHelper.item(PrettyImageHelper.ofFixedSizeSquare(graphic, 16), w.getName().getValue());
|
||||
var item = ContextMenuHelper.item(
|
||||
PrettyImageHelper.ofFixedSizeSquare(graphic, 16),
|
||||
w.getName().getValue());
|
||||
item.setOnAction(event -> {
|
||||
action.accept(w);
|
||||
contextMenu.hide();
|
||||
|
@ -83,7 +85,7 @@ public class StoreQuickAccessButtonComp extends Comp<CompStructure<Button>> {
|
|||
}
|
||||
|
||||
struc.get().setOnAction(event -> {
|
||||
ContextMenuHelper.toggleShow(cm,struc.get(), Side.RIGHT);
|
||||
ContextMenuHelper.toggleShow(cm, struc.get(), Side.RIGHT);
|
||||
event.consume();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -94,7 +94,9 @@ public class StoreSection {
|
|||
},
|
||||
category);
|
||||
var cached = ListBindingsHelper.cachedMappedContentBinding(
|
||||
topLevel, topLevel, storeEntryWrapper -> create(storeEntryWrapper, 1, all, entryFilter, filterString, category));
|
||||
topLevel,
|
||||
topLevel,
|
||||
storeEntryWrapper -> create(storeEntryWrapper, 1, all, entryFilter, filterString, category));
|
||||
var ordered = sorted(cached, category);
|
||||
var shown = ListBindingsHelper.filteredContentBinding(
|
||||
ordered,
|
||||
|
@ -133,7 +135,9 @@ public class StoreSection {
|
|||
return DataStorage.get().getStoreChildren(e.getEntry()).contains(other.getEntry());
|
||||
});
|
||||
var cached = ListBindingsHelper.cachedMappedContentBinding(
|
||||
allChildren, allChildren, entry1 -> create(entry1, depth + 1, all, entryFilter, filterString, category));
|
||||
allChildren,
|
||||
allChildren,
|
||||
entry1 -> create(entry1, depth + 1, all, entryFilter, filterString, category));
|
||||
var ordered = sorted(cached, category);
|
||||
var filtered = ListBindingsHelper.filteredContentBinding(
|
||||
ordered,
|
||||
|
|
|
@ -270,7 +270,9 @@ public class StoreViewState {
|
|||
return parent;
|
||||
}
|
||||
|
||||
return o1.nameProperty().getValue().compareToIgnoreCase(o2.nameProperty().getValue());
|
||||
return o1.nameProperty()
|
||||
.getValue()
|
||||
.compareToIgnoreCase(o2.nameProperty().getValue());
|
||||
}
|
||||
};
|
||||
return ListBindingsHelper.filteredContentBinding(
|
||||
|
|
|
@ -34,18 +34,10 @@ import java.util.regex.Pattern;
|
|||
|
||||
public class AppI18n {
|
||||
|
||||
@Value
|
||||
static class LoadedTranslations {
|
||||
|
||||
Map<String, String> translations;
|
||||
Map<String, String> markdownDocumentations;
|
||||
PrettyTime prettyTime;
|
||||
}
|
||||
|
||||
private static final Pattern VAR_PATTERN = Pattern.compile("\\$\\w+?\\$");
|
||||
private static AppI18n INSTANCE;
|
||||
private LoadedTranslations english;
|
||||
private final Property<LoadedTranslations> currentLanguage = new SimpleObjectProperty<>();
|
||||
private LoadedTranslations english;
|
||||
|
||||
public static void init() throws Exception {
|
||||
if (INSTANCE == null) {
|
||||
|
@ -54,39 +46,21 @@ public class AppI18n {
|
|||
INSTANCE.load();
|
||||
}
|
||||
|
||||
private void load() throws Exception {
|
||||
if (english == null) {
|
||||
english = load(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
if (AppPrefs.get() != null) {
|
||||
AppPrefs.get().language().subscribe(n -> {
|
||||
try {
|
||||
currentLanguage.setValue(n != null ? load(n.getLocale()) : null);
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static AppI18n get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private LoadedTranslations getLoaded() {
|
||||
return currentLanguage.getValue() != null ? currentLanguage.getValue() : english;
|
||||
}
|
||||
|
||||
public static ObservableValue<String> observable(String s, Object... vars) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var key = INSTANCE.getKey(s);
|
||||
return Bindings.createStringBinding(() -> {
|
||||
return Bindings.createStringBinding(
|
||||
() -> {
|
||||
return get(key, vars);
|
||||
}, INSTANCE.currentLanguage);
|
||||
},
|
||||
INSTANCE.currentLanguage);
|
||||
}
|
||||
|
||||
public static String get(String s, Object... vars) {
|
||||
|
@ -131,6 +105,26 @@ public class AppI18n {
|
|||
return "";
|
||||
}
|
||||
|
||||
private void load() throws Exception {
|
||||
if (english == null) {
|
||||
english = load(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
if (AppPrefs.get() != null) {
|
||||
AppPrefs.get().language().subscribe(n -> {
|
||||
try {
|
||||
currentLanguage.setValue(n != null ? load(n.getLocale()) : null);
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private LoadedTranslations getLoaded() {
|
||||
return currentLanguage.getValue() != null ? currentLanguage.getValue() : english;
|
||||
}
|
||||
|
||||
public String getKey(String s) {
|
||||
var key = s;
|
||||
if (!s.contains(".")) {
|
||||
|
@ -147,7 +141,8 @@ public class AppI18n {
|
|||
return s;
|
||||
}
|
||||
|
||||
if (currentLanguage.getValue() != null && currentLanguage.getValue().getTranslations().containsKey(key)) {
|
||||
if (currentLanguage.getValue() != null
|
||||
&& currentLanguage.getValue().getTranslations().containsKey(key)) {
|
||||
var localisedString = currentLanguage.getValue().getTranslations().get(key);
|
||||
return getValue(localisedString, vars);
|
||||
}
|
||||
|
@ -168,8 +163,10 @@ public class AppI18n {
|
|||
}
|
||||
|
||||
public String getMarkdownDocumentation(String name) {
|
||||
if (currentLanguage.getValue() != null && currentLanguage.getValue().getMarkdownDocumentations().containsKey(name)) {
|
||||
var localisedString = currentLanguage.getValue().getMarkdownDocumentations().get(name);
|
||||
if (currentLanguage.getValue() != null
|
||||
&& currentLanguage.getValue().getMarkdownDocumentations().containsKey(name)) {
|
||||
var localisedString =
|
||||
currentLanguage.getValue().getMarkdownDocumentations().get(name);
|
||||
return localisedString;
|
||||
}
|
||||
|
||||
|
@ -192,7 +189,8 @@ public class AppI18n {
|
|||
|
||||
var translations = new HashMap<String, String>();
|
||||
for (var module : AppExtensionManager.getInstance().getContentModules()) {
|
||||
var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())).resolve("strings");
|
||||
var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName()))
|
||||
.resolve("strings");
|
||||
if (!Files.exists(basePath)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -237,7 +235,8 @@ public class AppI18n {
|
|||
|
||||
var markdownDocumentations = new HashMap<String, String>();
|
||||
for (var module : AppExtensionManager.getInstance().getContentModules()) {
|
||||
var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())).resolve("texts");
|
||||
var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName()))
|
||||
.resolve("texts");
|
||||
if (!Files.exists(basePath)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -274,7 +273,15 @@ public class AppI18n {
|
|||
? AppPrefs.get().language().getValue().getLocale()
|
||||
: SupportedLocale.getEnglish().getLocale());
|
||||
|
||||
return new LoadedTranslations(translations,markdownDocumentations, prettyTime);
|
||||
return new LoadedTranslations(translations, markdownDocumentations, prettyTime);
|
||||
}
|
||||
|
||||
@Value
|
||||
static class LoadedTranslations {
|
||||
|
||||
Map<String, String> translations;
|
||||
Map<String, String> markdownDocumentations;
|
||||
PrettyTime prettyTime;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
|
|
|
@ -71,7 +71,10 @@ public class AppLayoutModel {
|
|||
|
||||
private List<Entry> createEntryList() {
|
||||
var l = new ArrayList<>(List.of(
|
||||
new Entry(AppI18n.observable("browser"), "mdi2f-file-cabinet", new BrowserSessionComp(BrowserSessionModel.DEFAULT)),
|
||||
new Entry(
|
||||
AppI18n.observable("browser"),
|
||||
"mdi2f-file-cabinet",
|
||||
new BrowserSessionComp(BrowserSessionModel.DEFAULT)),
|
||||
new Entry(AppI18n.observable("connections"), "mdi2c-connection", new StoreLayoutComp()),
|
||||
new Entry(AppI18n.observable("settings"), "mdsmz-miscellaneous_services", new AppPrefsComp()),
|
||||
new Entry(
|
||||
|
|
|
@ -48,7 +48,8 @@ public class AppTheme {
|
|||
|
||||
Runnable r = () -> {
|
||||
AppPrefs.get().theme.subscribe(t -> {
|
||||
Theme.ALL.forEach(theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId()));
|
||||
Theme.ALL.forEach(
|
||||
theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId()));
|
||||
if (t == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -88,7 +89,7 @@ public class AppTheme {
|
|||
var c = new WindowControl(stage);
|
||||
c.setWindowAttribute(20, AppPrefs.get().theme.getValue().isDark());
|
||||
stage.setWidth(stage.getWidth() + 1);
|
||||
Platform.runLater( () -> {
|
||||
Platform.runLater(() -> {
|
||||
stage.setWidth(stage.getWidth() - 1);
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
|
|
|
@ -53,7 +53,8 @@ public class AppWindowHelper {
|
|||
// This allows for assigning logos even if AppImages has not been initialized yet
|
||||
var dir = OsType.getLocal() == OsType.MACOS ? "img/logo/padded" : "img/logo/full";
|
||||
AppResources.with(AppResources.XPIPE_MODULE, dir, path -> {
|
||||
var size = switch (OsType.getLocal()) {
|
||||
var size =
|
||||
switch (OsType.getLocal()) {
|
||||
case OsType.Linux linux -> 128;
|
||||
case OsType.MacOs macOs -> 128;
|
||||
case OsType.Windows windows -> 32;
|
||||
|
|
|
@ -13,7 +13,8 @@ public class AppFontLoadingCheck {
|
|||
// This can fail if the found system fonts can somehow not be loaded
|
||||
Font.getDefault();
|
||||
} catch (Throwable e) {
|
||||
var event = ErrorEvent.fromThrowable("Unable to load fonts. Do you have valid font packages installed?", e).build();
|
||||
var event = ErrorEvent.fromThrowable("Unable to load fonts. Do you have valid font packages installed?", e)
|
||||
.build();
|
||||
// We can't use the normal error handling facility
|
||||
// as the platform reports as working but opening windows still does not work
|
||||
new LogErrorHandler().handle(event);
|
||||
|
|
|
@ -15,9 +15,9 @@ public class LaunchExchangeImpl extends LaunchExchange
|
|||
public Response handleRequest(BeaconHandler handler, Request msg) throws Exception {
|
||||
var store = getStoreEntryById(msg.getId(), false);
|
||||
if (store.getStore() instanceof LaunchableStore s) {
|
||||
// var command = s.prepareLaunchCommand()
|
||||
// .prepareTerminalOpen(TerminalInitScriptConfig.ofName(store.getName()), sc -> null);
|
||||
// return Response.builder().command(split(command)).build();
|
||||
// var command = s.prepareLaunchCommand()
|
||||
// .prepareTerminalOpen(TerminalInitScriptConfig.ofName(store.getName()), sc -> null);
|
||||
// return Response.builder().command(split(command)).build();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(store.getName() + " is not launchable");
|
||||
|
|
|
@ -12,6 +12,28 @@ import java.util.stream.Collectors;
|
|||
|
||||
public class MessageExchangeImpls {
|
||||
|
||||
private static List<MessageExchangeImpl<?, ?>> ALL;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <RQ extends RequestMessage, RS extends ResponseMessage> Optional<MessageExchangeImpl<RQ, RS>> byId(
|
||||
String name) {
|
||||
var r = ALL.stream().filter(d -> d.getId().equals(name)).findAny();
|
||||
return Optional.ofNullable((MessageExchangeImpl<RQ, RS>) r.orElse(null));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <RQ extends RequestMessage, RS extends ResponseMessage>
|
||||
Optional<MessageExchangeImpl<RQ, RS>> byRequest(RQ req) {
|
||||
var r = ALL.stream()
|
||||
.filter(d -> d.getRequestClass().equals(req.getClass()))
|
||||
.findAny();
|
||||
return Optional.ofNullable((MessageExchangeImpl<RQ, RS>) r.orElse(null));
|
||||
}
|
||||
|
||||
public static List<MessageExchangeImpl<?, ?>> getAll() {
|
||||
return ALL;
|
||||
}
|
||||
|
||||
public static class Loader implements ModuleLayerLoader {
|
||||
|
||||
@Override
|
||||
|
@ -36,27 +58,4 @@ public class MessageExchangeImpls {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static List<MessageExchangeImpl<?, ?>> ALL;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <RQ extends RequestMessage, RS extends ResponseMessage> Optional<MessageExchangeImpl<RQ, RS>> byId(
|
||||
String name) {
|
||||
var r = ALL.stream().filter(d -> d.getId().equals(name)).findAny();
|
||||
return Optional.ofNullable((MessageExchangeImpl<RQ, RS>) r.orElse(null));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <RQ extends RequestMessage, RS extends ResponseMessage>
|
||||
Optional<MessageExchangeImpl<RQ, RS>> byRequest(RQ req) {
|
||||
var r = ALL.stream()
|
||||
.filter(d -> d.getRequestClass().equals(req.getClass()))
|
||||
.findAny();
|
||||
return Optional.ofNullable((MessageExchangeImpl<RQ, RS>) r.orElse(null));
|
||||
}
|
||||
|
||||
public static List<MessageExchangeImpl<?, ?>> getAll() {
|
||||
return ALL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,6 +143,5 @@ public interface ActionProvider {
|
|||
})
|
||||
.toList());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,37 +14,6 @@ import java.util.stream.Collectors;
|
|||
|
||||
public class DataStoreProviders {
|
||||
|
||||
public static class Loader implements ModuleLayerLoader {
|
||||
|
||||
@Override
|
||||
public void init(ModuleLayer layer) {
|
||||
TrackEvent.info("Loading extension providers ...");
|
||||
ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream().map(ServiceLoader.Provider::get).collect(Collectors.toList());
|
||||
ALL.removeIf(p -> {
|
||||
try {
|
||||
if (!p.init()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
p.validate();
|
||||
return false;
|
||||
} catch (Throwable e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
for (DataStoreProvider p : getAll()) {
|
||||
TrackEvent.trace("Loaded data store provider " + p.getId());
|
||||
JacksonMapper.configure(objectMapper -> {
|
||||
for (Class<?> storeClass : p.getStoreClasses()) {
|
||||
objectMapper.registerSubtypes(new NamedType(storeClass));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<DataStoreProvider> ALL;
|
||||
|
||||
public static void postInit(ModuleLayer layer) {
|
||||
|
@ -100,4 +69,37 @@ public class DataStoreProviders {
|
|||
public static List<DataStoreProvider> getAll() {
|
||||
return ALL;
|
||||
}
|
||||
|
||||
public static class Loader implements ModuleLayerLoader {
|
||||
|
||||
@Override
|
||||
public void init(ModuleLayer layer) {
|
||||
TrackEvent.info("Loading extension providers ...");
|
||||
ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream()
|
||||
.map(ServiceLoader.Provider::get)
|
||||
.collect(Collectors.toList());
|
||||
ALL.removeIf(p -> {
|
||||
try {
|
||||
if (!p.init()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
p.validate();
|
||||
return false;
|
||||
} catch (Throwable e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
for (DataStoreProvider p : getAll()) {
|
||||
TrackEvent.trace("Loaded data store provider " + p.getId());
|
||||
JacksonMapper.configure(objectMapper -> {
|
||||
for (Class<?> storeClass : p.getStoreClasses()) {
|
||||
objectMapper.registerSubtypes(new NamedType(storeClass));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,9 +36,7 @@ public interface PrefsChoiceValue extends Translatable {
|
|||
throw new AssertionError();
|
||||
}
|
||||
|
||||
return all.stream()
|
||||
.filter(t -> ((PrefsChoiceValue) t).isSelectable())
|
||||
.toList();
|
||||
return all.stream().filter(t -> ((PrefsChoiceValue) t).isSelectable()).toList();
|
||||
}
|
||||
|
||||
default boolean isAvailable() {
|
||||
|
|
|
@ -34,6 +34,5 @@ public abstract class PrefsProvider {
|
|||
.map(ServiceLoader.Provider::get)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,5 @@ public abstract class ScanProvider {
|
|||
scanProvider -> scanProvider.getClass().getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,10 @@ public class ContextMenuAugment<S extends CompStructure<?>> implements Augment<S
|
|||
private final Predicate<KeyEvent> keyEventCheck;
|
||||
private final Supplier<ContextMenu> contextMenu;
|
||||
|
||||
public ContextMenuAugment(Predicate<MouseEvent> mouseEventCheck, Predicate<KeyEvent> keyEventCheck, Supplier<ContextMenu> contextMenu) {
|
||||
public ContextMenuAugment(
|
||||
Predicate<MouseEvent> mouseEventCheck,
|
||||
Predicate<KeyEvent> keyEventCheck,
|
||||
Supplier<ContextMenu> contextMenu) {
|
||||
this.mouseEventCheck = mouseEventCheck;
|
||||
this.keyEventCheck = keyEventCheck;
|
||||
this.contextMenu = contextMenu;
|
||||
|
|
|
@ -53,7 +53,9 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
|||
.grow(false, true);
|
||||
|
||||
var fileBrowseButton = new ButtonComp(null, new FontIcon("mdi2f-folder-open-outline"), () -> {
|
||||
BrowserChooserComp.openSingleFile(() -> fileSystem.getValue(), fileStore -> {
|
||||
BrowserChooserComp.openSingleFile(
|
||||
() -> fileSystem.getValue(),
|
||||
fileStore -> {
|
||||
if (fileStore == null) {
|
||||
filePath.setValue(null);
|
||||
fileSystem.setValue(null);
|
||||
|
@ -61,7 +63,8 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
|||
filePath.setValue(fileStore.getPath());
|
||||
fileSystem.setValue(fileStore.getFileSystem());
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
false);
|
||||
})
|
||||
.styleClass(Styles.CENTER_PILL)
|
||||
.grow(false, true);
|
||||
|
@ -85,7 +88,8 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
|||
return;
|
||||
}
|
||||
|
||||
if (filePath.getValue() == null || ContextualFileReference.of(filePath.getValue()).isInDataDirectory()) {
|
||||
if (filePath.getValue() == null
|
||||
|| ContextualFileReference.of(filePath.getValue()).isInDataDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package io.xpipe.app.fxcomps.impl;
|
|||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
|
|
@ -71,7 +71,8 @@ public class StoreCategoryComp extends SimpleComp {
|
|||
var showing = new SimpleBooleanProperty();
|
||||
var settings = new IconButtonComp("mdomz-settings")
|
||||
.styleClass("settings")
|
||||
.apply(new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> {
|
||||
.apply(new ContextMenuAugment<>(
|
||||
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> {
|
||||
var cm = createContextMenu(name);
|
||||
showing.bind(cm.showingProperty());
|
||||
return cm;
|
||||
|
@ -102,11 +103,13 @@ public class StoreCategoryComp extends SimpleComp {
|
|||
.accessibleText(category.nameProperty())
|
||||
.grow(true, false);
|
||||
categoryButton.apply(new ContextMenuAugment<>(
|
||||
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, keyEvent -> keyEvent.getCode() == KeyCode.SPACE, () -> createContextMenu(name)));
|
||||
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY,
|
||||
keyEvent -> keyEvent.getCode() == KeyCode.SPACE,
|
||||
() -> createContextMenu(name)));
|
||||
|
||||
var l = category.getChildren()
|
||||
.sorted(Comparator.comparing(
|
||||
storeCategoryWrapper -> storeCategoryWrapper.nameProperty().getValue().toLowerCase(Locale.ROOT)));
|
||||
.sorted(Comparator.comparing(storeCategoryWrapper ->
|
||||
storeCategoryWrapper.nameProperty().getValue().toLowerCase(Locale.ROOT)));
|
||||
var children = new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper));
|
||||
|
||||
var emptyBinding = Bindings.isEmpty(category.getChildren());
|
||||
|
|
|
@ -17,7 +17,8 @@ public class StringSourceComp extends SimpleComp {
|
|||
private final Property<DataStoreEntryRef<ShellStore>> fileSystem;
|
||||
private final Property<StringSource> stringSource;
|
||||
|
||||
public <T extends ShellStore> StringSourceComp(ObservableValue<DataStoreEntryRef<T>> fileSystem, Property<StringSource> stringSource) {
|
||||
public <T extends ShellStore> StringSourceComp(
|
||||
ObservableValue<DataStoreEntryRef<T>> fileSystem, Property<StringSource> stringSource) {
|
||||
this.stringSource = stringSource;
|
||||
this.fileSystem = new SimpleObjectProperty<>();
|
||||
fileSystem.subscribe(val -> {
|
||||
|
@ -27,9 +28,13 @@ public class StringSourceComp extends SimpleComp {
|
|||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var inPlace = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null);
|
||||
var inPlace =
|
||||
new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null);
|
||||
var fs = stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null;
|
||||
var file = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.File f ? f.getFile().serialize() : null);
|
||||
var file = new SimpleObjectProperty<>(
|
||||
stringSource.getValue() instanceof StringSource.File f
|
||||
? f.getFile().serialize()
|
||||
: null);
|
||||
var showText = new SimpleBooleanProperty(inPlace.get() != null);
|
||||
|
||||
var stringField = new TextAreaComp(inPlace);
|
||||
|
@ -40,7 +45,8 @@ public class StringSourceComp extends SimpleComp {
|
|||
var tr = stringField.createRegion();
|
||||
var button = new IconButtonComp("mdi2c-checkbox-marked-outline", () -> {
|
||||
showText.set(!showText.getValue());
|
||||
}).createRegion();
|
||||
})
|
||||
.createRegion();
|
||||
AnchorPane.setBottomAnchor(button, 10.0);
|
||||
AnchorPane.setRightAnchor(button, 10.0);
|
||||
var anchorPane = new AnchorPane(tr, button);
|
||||
|
|
|
@ -68,7 +68,7 @@ public class SvgView {
|
|||
wv.setDisable(true);
|
||||
|
||||
wv.getEngine().loadContent(svgContent.getValue() != null ? getHtml(svgContent.getValue()) : null);
|
||||
svgContent.subscribe( n -> {
|
||||
svgContent.subscribe(n -> {
|
||||
if (n == null) {
|
||||
wv.setOpacity(0.0);
|
||||
return;
|
||||
|
|
|
@ -22,29 +22,19 @@ public class TooltipAugment<S extends CompStructure<?>> implements Augment<S> {
|
|||
this.text = AppI18n.observable(key);
|
||||
}
|
||||
|
||||
private static class FixedTooltip extends Tooltip {
|
||||
|
||||
public FixedTooltip() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void show() {
|
||||
Window owner = getOwnerWindow();
|
||||
if (owner.isFocused())
|
||||
super.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void augment(S struc) {
|
||||
var region = struc.get();
|
||||
var tt = new FixedTooltip();
|
||||
if (Shortcuts.getDisplayShortcut(region) != null) {
|
||||
var s = AppI18n.observable("shortcut");
|
||||
var binding = Bindings.createStringBinding(() -> {
|
||||
return text.getValue() + "\n\n" + s.getValue() + ": " + Shortcuts.getDisplayShortcut(region).getDisplayText();
|
||||
}, text, s);
|
||||
var binding = Bindings.createStringBinding(
|
||||
() -> {
|
||||
return text.getValue() + "\n\n" + s.getValue() + ": "
|
||||
+ Shortcuts.getDisplayShortcut(region).getDisplayText();
|
||||
},
|
||||
text,
|
||||
s);
|
||||
tt.textProperty().bind(binding);
|
||||
} else {
|
||||
tt.textProperty().bind(text);
|
||||
|
@ -56,4 +46,17 @@ public class TooltipAugment<S extends CompStructure<?>> implements Augment<S> {
|
|||
|
||||
Tooltip.install(struc.get(), tt);
|
||||
}
|
||||
|
||||
private static class FixedTooltip extends Tooltip {
|
||||
|
||||
public FixedTooltip() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void show() {
|
||||
Window owner = getOwnerWindow();
|
||||
if (owner.isFocused()) super.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,8 @@ public abstract class LauncherInput {
|
|||
|
||||
var dir = Files.isDirectory(file) ? file : file.getParent();
|
||||
AppLayoutModel.get().selectBrowser();
|
||||
BrowserSessionModel.DEFAULT.openFileSystemAsync(DataStorage.get().local().ref(), model -> dir.toString(), null);
|
||||
BrowserSessionModel.DEFAULT.openFileSystemAsync(
|
||||
DataStorage.get().local().ref(), model -> dir.toString(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,18 +24,6 @@ public class AppearanceCategory extends AppPrefsCategory {
|
|||
return "appearance";
|
||||
}
|
||||
|
||||
private Comp<?> languageChoice() {
|
||||
var prefs = AppPrefs.get();
|
||||
var c = ChoiceComp.ofTranslatable(prefs.language, SupportedLocale.ALL, false);
|
||||
var visit = new ButtonComp(AppI18n.observable("translate"), new FontIcon("mdi2w-web"), () -> {
|
||||
Hyperlinks.open(Hyperlinks.TRANSLATE);
|
||||
});
|
||||
return new HorizontalComp(List.of(c, visit)).apply(struc -> {
|
||||
struc.get().setAlignment(Pos.CENTER_LEFT);
|
||||
struc.get().setSpacing(10);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> create() {
|
||||
var prefs = AppPrefs.get();
|
||||
|
@ -43,9 +31,7 @@ public class AppearanceCategory extends AppPrefsCategory {
|
|||
.addTitle("uiOptions")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("language")
|
||||
.addComp(
|
||||
languageChoice(),
|
||||
prefs.language)
|
||||
.addComp(languageChoice(), prefs.language)
|
||||
.nameAndDescription("theme")
|
||||
.addComp(
|
||||
ChoiceComp.ofTranslatable(prefs.theme, AppTheme.Theme.ALL, false)
|
||||
|
@ -83,4 +69,16 @@ public class AppearanceCategory extends AppPrefsCategory {
|
|||
.addToggle(prefs.enforceWindowModality))
|
||||
.buildComp();
|
||||
}
|
||||
|
||||
private Comp<?> languageChoice() {
|
||||
var prefs = AppPrefs.get();
|
||||
var c = ChoiceComp.ofTranslatable(prefs.language, SupportedLocale.ALL, false);
|
||||
var visit = new ButtonComp(AppI18n.observable("translate"), new FontIcon("mdi2w-web"), () -> {
|
||||
Hyperlinks.open(Hyperlinks.TRANSLATE);
|
||||
});
|
||||
return new HorizontalComp(List.of(c, visit)).apply(struc -> {
|
||||
struc.get().setAlignment(Pos.CENTER_LEFT);
|
||||
struc.get().setSpacing(10);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,8 +106,8 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
|||
|
||||
var format =
|
||||
customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE";
|
||||
ExternalApplicationHelper.startAsync(
|
||||
CommandBuilder.of().add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", file.toString())));
|
||||
ExternalApplicationHelper.startAsync(CommandBuilder.of()
|
||||
.add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", file.toString())));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -199,8 +199,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
|||
throw new IOException("Application " + applicationName + ".app not found");
|
||||
}
|
||||
|
||||
ExternalApplicationHelper.startAsync(
|
||||
CommandBuilder.of()
|
||||
ExternalApplicationHelper.startAsync(CommandBuilder.of()
|
||||
.add("open", "-a")
|
||||
.addFile(execFile.orElseThrow().toString())
|
||||
.addFile(file.toString()));
|
||||
|
|
|
@ -14,44 +14,14 @@ import java.util.function.Supplier;
|
|||
|
||||
public interface ExternalRdpClientType extends PrefsChoiceValue {
|
||||
|
||||
@Value
|
||||
class LaunchConfiguration {
|
||||
String title;
|
||||
RdpConfig config;
|
||||
UUID storeId;
|
||||
SecretRetrievalStrategy password;
|
||||
}
|
||||
|
||||
abstract class PathCheckType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType {
|
||||
|
||||
public PathCheckType(String id, String executable, boolean explicityAsync) {
|
||||
super(id, executable, explicityAsync);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MacOsType extends ExternalApplicationType.MacApplication implements ExternalRdpClientType {
|
||||
|
||||
public MacOsType(String id, String applicationName) {
|
||||
super(id, applicationName);
|
||||
}
|
||||
}
|
||||
|
||||
void launch(LaunchConfiguration configuration) throws Exception;
|
||||
|
||||
default Path writeConfig(RdpConfig input) throws Exception {
|
||||
var file = LocalShell.getShell().getSystemTemporaryDirectory().join("exec-" + ScriptHelper.getScriptId() + ".rdp");
|
||||
var string = input.toString();
|
||||
Files.writeString(file.toLocalPath(), string);
|
||||
return file.toLocalPath();
|
||||
}
|
||||
|
||||
ExternalRdpClientType MSTSC = new PathCheckType("app.mstsc", "mstsc.exe", true) {
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var adaptedRdpConfig = getAdaptedConfig(configuration);
|
||||
var file = writeConfig(adaptedRdpConfig);
|
||||
LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().add(executable).addFile(file.toString()));
|
||||
LocalShell.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of().add(executable).addFile(file.toString()));
|
||||
}
|
||||
|
||||
private RdpConfig getAdaptedConfig(LaunchConfiguration configuration) throws Exception {
|
||||
|
@ -85,17 +55,18 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
|
|||
return cmd.readStdoutOrThrow();
|
||||
}
|
||||
};
|
||||
|
||||
ExternalRdpClientType REMMINA = new PathCheckType("app.remmina", "remmina", true) {
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var file = writeConfig(configuration.getConfig());
|
||||
LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().add(executable).add("-c").addFile(file.toString()));
|
||||
LocalShell.getShell()
|
||||
.executeSimpleCommand(
|
||||
CommandBuilder.of().add(executable).add("-c").addFile(file.toString()));
|
||||
}
|
||||
};
|
||||
|
||||
ExternalRdpClientType MICROSOFT_REMOTE_DESKTOP_MACOS_APP = new MacOsType("app.microsoftRemoteDesktopApp", "Microsoft Remote Desktop.app") {
|
||||
ExternalRdpClientType MICROSOFT_REMOTE_DESKTOP_MACOS_APP =
|
||||
new MacOsType("app.microsoftRemoteDesktopApp", "Microsoft Remote Desktop.app") {
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
|
@ -107,36 +78,10 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
|
|||
.addFile(file.toString()));
|
||||
}
|
||||
};
|
||||
|
||||
class CustomType extends ExternalApplicationType implements ExternalRdpClientType {
|
||||
|
||||
public CustomType() {
|
||||
super("app.custom");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var customCommand = AppPrefs.get().customRdpClientCommand().getValue();
|
||||
if (customCommand == null || customCommand.isBlank()) {
|
||||
throw ErrorEvent.expected(new IllegalStateException("No custom RDP command specified"));
|
||||
}
|
||||
|
||||
var format = customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE";
|
||||
ExternalApplicationHelper.startAsync(CommandBuilder.of().add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", writeConfig(configuration.getConfig()).toString())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ExternalRdpClientType CUSTOM = new CustomType();
|
||||
|
||||
List<ExternalRdpClientType> WINDOWS_CLIENTS = List.of(MSTSC);
|
||||
List<ExternalRdpClientType> LINUX_CLIENTS = List.of(REMMINA);
|
||||
List<ExternalRdpClientType> MACOS_CLIENTS = List.of(MICROSOFT_REMOTE_DESKTOP_MACOS_APP);
|
||||
|
||||
@SuppressWarnings("TrivialFunctionalExpressionUsage")
|
||||
List<ExternalRdpClientType> ALL = ((Supplier<List<ExternalRdpClientType>>) () -> {
|
||||
var all = new ArrayList<ExternalRdpClientType>();
|
||||
|
@ -151,7 +96,8 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
|
|||
}
|
||||
all.add(CUSTOM);
|
||||
return all;
|
||||
}).get();
|
||||
})
|
||||
.get();
|
||||
|
||||
static ExternalRdpClientType determineDefault() {
|
||||
return ALL.stream()
|
||||
|
@ -160,4 +106,64 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
|
|||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
void launch(LaunchConfiguration configuration) throws Exception;
|
||||
|
||||
default Path writeConfig(RdpConfig input) throws Exception {
|
||||
var file =
|
||||
LocalShell.getShell().getSystemTemporaryDirectory().join("exec-" + ScriptHelper.getScriptId() + ".rdp");
|
||||
var string = input.toString();
|
||||
Files.writeString(file.toLocalPath(), string);
|
||||
return file.toLocalPath();
|
||||
}
|
||||
|
||||
@Value
|
||||
class LaunchConfiguration {
|
||||
String title;
|
||||
RdpConfig config;
|
||||
UUID storeId;
|
||||
SecretRetrievalStrategy password;
|
||||
}
|
||||
|
||||
abstract class PathCheckType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType {
|
||||
|
||||
public PathCheckType(String id, String executable, boolean explicityAsync) {
|
||||
super(id, executable, explicityAsync);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MacOsType extends ExternalApplicationType.MacApplication implements ExternalRdpClientType {
|
||||
|
||||
public MacOsType(String id, String applicationName) {
|
||||
super(id, applicationName);
|
||||
}
|
||||
}
|
||||
|
||||
class CustomType extends ExternalApplicationType implements ExternalRdpClientType {
|
||||
|
||||
public CustomType() {
|
||||
super("app.custom");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
var customCommand = AppPrefs.get().customRdpClientCommand().getValue();
|
||||
if (customCommand == null || customCommand.isBlank()) {
|
||||
throw ErrorEvent.expected(new IllegalStateException("No custom RDP command specified"));
|
||||
}
|
||||
|
||||
var format =
|
||||
customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE";
|
||||
ExternalApplicationHelper.startAsync(CommandBuilder.of()
|
||||
.add(ExternalApplicationHelper.replaceFileArgument(
|
||||
format,
|
||||
"FILE",
|
||||
writeConfig(configuration.getConfig()).toString())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,7 @@ public class RdpCategory extends AppPrefsCategory {
|
|||
.nameAndDescription("customRdpClientCommand")
|
||||
.addComp(new TextFieldComp(prefs.customRdpClientCommand, true)
|
||||
.apply(struc -> struc.get().setPromptText("myrdpclient -c $FILE"))
|
||||
.hide(prefs.rdpClientType.isNotEqualTo(ExternalRdpClientType.CUSTOM)))
|
||||
)
|
||||
.hide(prefs.rdpClientType.isNotEqualTo(ExternalRdpClientType.CUSTOM))))
|
||||
.buildComp();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,15 +14,19 @@ import java.util.Locale;
|
|||
@Getter
|
||||
public class SupportedLocale implements PrefsChoiceValue {
|
||||
|
||||
public static List<SupportedLocale> ALL = AppProperties.get().getLanguages().stream().map(s -> new SupportedLocale(Locale.of(s), s)).toList();
|
||||
|
||||
public static SupportedLocale getEnglish() {
|
||||
return ALL.stream().filter(supportedLocale -> supportedLocale.getId().equals("en")).findFirst().orElseThrow();
|
||||
}
|
||||
|
||||
public static List<SupportedLocale> ALL = AppProperties.get().getLanguages().stream()
|
||||
.map(s -> new SupportedLocale(Locale.of(s), s))
|
||||
.toList();
|
||||
private final Locale locale;
|
||||
private final String id;
|
||||
|
||||
public static SupportedLocale getEnglish() {
|
||||
return ALL.stream()
|
||||
.filter(supportedLocale -> supportedLocale.getId().equals("en"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> toTranslatedString() {
|
||||
return new SimpleStringProperty(locale.getDisplayName(locale));
|
||||
|
|
|
@ -30,57 +30,6 @@ public class TerminalCategory extends AppPrefsCategory {
|
|||
return "terminal";
|
||||
}
|
||||
|
||||
private Comp<?> terminalChoice() {
|
||||
var prefs = AppPrefs.get();
|
||||
var c = ChoiceComp.ofTranslatable(
|
||||
prefs.terminalType, PrefsChoiceValue.getSupported(ExternalTerminalType.class), false);
|
||||
c.apply(struc -> {
|
||||
struc.get().setCellFactory(param -> {
|
||||
return new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(ExternalTerminalType item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
setText(item.toTranslatedString().getValue());
|
||||
if (item != ExternalTerminalType.CUSTOM) {
|
||||
var graphic = new FontIcon(item.isRecommended() ? "mdi2c-check-decagram" : "mdi2a-alert-circle-check");
|
||||
graphic.setFill(item.isRecommended() ? Color.GREEN : Color.ORANGE);
|
||||
setGraphic(graphic);
|
||||
} else {
|
||||
setGraphic(new FontIcon("mdi2m-minus-circle"));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
var visit = new ButtonComp(AppI18n.observable("website"), new FontIcon("mdi2w-web"), () -> {
|
||||
var t = prefs.terminalType().getValue();
|
||||
if (t == null || t.getWebsite() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Hyperlinks.open(t.getWebsite());
|
||||
});
|
||||
var visitVisible = Bindings.createBooleanBinding(() -> {
|
||||
var t = prefs.terminalType().getValue();
|
||||
if (t == null || t.getWebsite() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}, prefs.terminalType());
|
||||
visit.visible(visitVisible);
|
||||
|
||||
return new HorizontalComp(List.of(c, visit)).apply(struc -> {
|
||||
struc.get().setAlignment(Pos.CENTER_LEFT);
|
||||
struc.get().setSpacing(10);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> create() {
|
||||
var prefs = AppPrefs.get();
|
||||
|
@ -117,4 +66,58 @@ public class TerminalCategory extends AppPrefsCategory {
|
|||
.addToggle(prefs.clearTerminalOnInit))
|
||||
.buildComp();
|
||||
}
|
||||
|
||||
private Comp<?> terminalChoice() {
|
||||
var prefs = AppPrefs.get();
|
||||
var c = ChoiceComp.ofTranslatable(
|
||||
prefs.terminalType, PrefsChoiceValue.getSupported(ExternalTerminalType.class), false);
|
||||
c.apply(struc -> {
|
||||
struc.get().setCellFactory(param -> {
|
||||
return new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(ExternalTerminalType item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
setText(item.toTranslatedString().getValue());
|
||||
if (item != ExternalTerminalType.CUSTOM) {
|
||||
var graphic = new FontIcon(
|
||||
item.isRecommended() ? "mdi2c-check-decagram" : "mdi2a-alert-circle-check");
|
||||
graphic.setFill(item.isRecommended() ? Color.GREEN : Color.ORANGE);
|
||||
setGraphic(graphic);
|
||||
} else {
|
||||
setGraphic(new FontIcon("mdi2m-minus-circle"));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
var visit = new ButtonComp(AppI18n.observable("website"), new FontIcon("mdi2w-web"), () -> {
|
||||
var t = prefs.terminalType().getValue();
|
||||
if (t == null || t.getWebsite() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Hyperlinks.open(t.getWebsite());
|
||||
});
|
||||
var visitVisible = Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
var t = prefs.terminalType().getValue();
|
||||
if (t == null || t.getWebsite() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
prefs.terminalType());
|
||||
visit.visible(visitVisible);
|
||||
|
||||
return new HorizontalComp(List.of(c, visit)).apply(struc -> {
|
||||
struc.get().setAlignment(Pos.CENTER_LEFT);
|
||||
struc.get().setSpacing(10);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
|
|||
XPipeInstallation.getCurrentInstallationBasePath()
|
||||
.toString(),
|
||||
XPipeInstallation.getDaemonDebugScriptPath(OsType.getLocal()));
|
||||
TerminalLauncher.openDirect("XPipe Debug", sc -> sc.getShellDialect().runScriptCommand(sc, script));
|
||||
TerminalLauncher.openDirect("XPipe Debug", sc -> sc.getShellDialect()
|
||||
.runScriptCommand(sc, script));
|
||||
});
|
||||
e.consume();
|
||||
})
|
||||
|
|
|
@ -5,6 +5,30 @@ import io.xpipe.core.process.CommandBuilder;
|
|||
|
||||
public interface AlacrittyTerminalType extends ExternalTerminalType {
|
||||
|
||||
ExternalTerminalType ALACRITTY_WINDOWS = new Windows();
|
||||
ExternalTerminalType ALACRITTY_LINUX = new Linux();
|
||||
ExternalTerminalType ALACRITTY_MAC_OS = new MacOs();
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getWebsite() {
|
||||
return "https://github.com/alacritty/alacritty";
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
static class Windows extends SimplePathType implements AlacrittyTerminalType {
|
||||
|
||||
public Windows() {
|
||||
|
@ -15,11 +39,11 @@ public interface AlacrittyTerminalType extends ExternalTerminalType {
|
|||
protected CommandBuilder toCommand(LaunchConfiguration configuration) {
|
||||
var b = CommandBuilder.of();
|
||||
|
||||
// if (configuration.getColor() != null) {
|
||||
// b.add("-o")
|
||||
// .addQuoted("colors.primary.background='%s'"
|
||||
// .formatted(configuration.getColor().toHexString()));
|
||||
// }
|
||||
// if (configuration.getColor() != null) {
|
||||
// b.add("-o")
|
||||
// .addQuoted("colors.primary.background='%s'"
|
||||
// .formatted(configuration.getColor().toHexString()));
|
||||
// }
|
||||
|
||||
// Alacritty is bugged and will not accept arguments with spaces even if they are correctly passed/escaped
|
||||
// So this will not work when the script file has spaces
|
||||
|
@ -28,7 +52,6 @@ public interface AlacrittyTerminalType extends ExternalTerminalType {
|
|||
.add("-e")
|
||||
.add(configuration.getDialectLaunchCommand());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Linux extends SimplePathType implements AlacrittyTerminalType {
|
||||
|
@ -45,31 +68,6 @@ public interface AlacrittyTerminalType extends ExternalTerminalType {
|
|||
.add("-e")
|
||||
.addFile(configuration.getScriptFile());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ExternalTerminalType ALACRITTY_WINDOWS = new Windows();
|
||||
ExternalTerminalType ALACRITTY_LINUX = new Linux();
|
||||
ExternalTerminalType ALACRITTY_MAC_OS = new MacOs();
|
||||
|
||||
@Override
|
||||
default String getWebsite() {
|
||||
return "https://github.com/alacritty/alacritty";
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
class MacOs extends MacOsType implements AlacrittyTerminalType {
|
||||
|
|
|
@ -39,7 +39,8 @@ public class CustomTerminalType extends ExternalApplicationType implements Exter
|
|||
|
||||
var format = custom.toLowerCase(Locale.ROOT).contains("$cmd") ? custom : custom + " $CMD";
|
||||
try (var pc = LocalShell.getShell()) {
|
||||
var toExecute = ExternalApplicationHelper.replaceFileArgument(format, "CMD", configuration.getScriptFile().toString());
|
||||
var toExecute = ExternalApplicationHelper.replaceFileArgument(
|
||||
format, "CMD", configuration.getScriptFile().toString());
|
||||
// We can't be sure whether the command is blocking or not, so always make it not blocking
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
toExecute = "start \"" + configuration.getCleanTitle() + "\" " + toExecute;
|
||||
|
|
|
@ -3,7 +3,8 @@ package io.xpipe.app.terminal;
|
|||
import io.xpipe.app.ext.PrefsChoiceValue;
|
||||
import io.xpipe.app.prefs.ExternalApplicationType;
|
||||
import io.xpipe.app.storage.DataStoreColor;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.app.util.CommandSupport;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.process.*;
|
||||
import io.xpipe.core.store.FilePath;
|
||||
import lombok.Getter;
|
||||
|
@ -13,7 +14,10 @@ import lombok.With;
|
|||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface ExternalTerminalType extends PrefsChoiceValue {
|
||||
|
@ -21,12 +25,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
ExternalTerminalType CMD = new SimplePathType("app.cmd", "cmd.exe", true) {
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -48,12 +52,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
ExternalTerminalType POWERSHELL = new SimplePathType("app.powershell", "powershell", true) {
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -88,12 +92,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
ExternalTerminalType PWSH = new SimplePathType("app.pwsh", "pwsh", true) {
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -118,8 +122,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType GNOME_TERMINAL = new PathCheckType("app.gnomeTerminal", "gnome-terminal", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -128,8 +132,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,12 +156,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
ExternalTerminalType KONSOLE = new SimplePathType("app.konsole", "konsole", true) {
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -176,18 +180,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType XFCE = new SimplePathType("app.xfce", "xfce4-terminal", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -202,18 +205,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType ELEMENTARY = new SimplePathType("app.elementaryTerminal", "io.elementary.terminal", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -224,19 +226,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType TILIX = new SimplePathType("app.tilix", "tilix", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -250,18 +251,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType TERMINATOR = new SimplePathType("app.terminator", "terminator", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -277,18 +277,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType TERMINOLOGY = new SimplePathType("app.terminology", "terminology", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -304,19 +303,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType COOL_RETRO_TERM = new SimplePathType("app.coolRetroTerm", "cool-retro-term", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -330,18 +328,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType GUAKE = new SimplePathType("app.guake", "guake", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -357,18 +354,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType TILDA = new SimplePathType("app.tilda", "tilda", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -379,19 +375,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType XTERM = new SimplePathType("app.xterm", "xterm", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -405,19 +400,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType DEEPIN_TERMINAL = new SimplePathType("app.deepinTerminal", "deepin-terminal", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRecommended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -427,8 +421,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType Q_TERMINAL = new SimplePathType("app.qTerminal", "qterminal", true) {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -436,10 +430,9 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -449,8 +442,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType MACOS_TERMINAL = new MacOsType("app.macosTerminal", "Terminal") {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -459,8 +452,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
return false;
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -480,7 +473,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
};
|
||||
ExternalTerminalType ITERM2 = new MacOsType("app.iterm2", "iTerm") {
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -490,7 +483,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -519,7 +512,11 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
create window with default profile command "%s"
|
||||
end tell
|
||||
""",
|
||||
a, a, a, a, configuration.getScriptFile().toString().replaceAll("\"", "\\\\\"")))
|
||||
a,
|
||||
a,
|
||||
a,
|
||||
a,
|
||||
configuration.getScriptFile().toString().replaceAll("\"", "\\\\\"")))
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +524,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
ExternalTerminalType WARP = new MacOsType("app.warp", "Warp") {
|
||||
|
||||
@Override
|
||||
public boolean supportsColoredTitle() {
|
||||
public boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -537,7 +534,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTabs() {
|
||||
public boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -582,8 +579,14 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
XTERM,
|
||||
DEEPIN_TERMINAL,
|
||||
Q_TERMINAL);
|
||||
List<ExternalTerminalType> MACOS_TERMINALS =
|
||||
List.of(ITERM2, TabbyTerminalType.TABBY_MAC_OS, AlacrittyTerminalType.ALACRITTY_MAC_OS, KittyTerminalType.KITTY_MACOS, WARP, WezTerminalType.WEZTERM_MAC_OS, MACOS_TERMINAL);
|
||||
List<ExternalTerminalType> MACOS_TERMINALS = List.of(
|
||||
ITERM2,
|
||||
TabbyTerminalType.TABBY_MAC_OS,
|
||||
AlacrittyTerminalType.ALACRITTY_MAC_OS,
|
||||
KittyTerminalType.KITTY_MACOS,
|
||||
WARP,
|
||||
WezTerminalType.WEZTERM_MAC_OS,
|
||||
MACOS_TERMINAL);
|
||||
|
||||
@SuppressWarnings("TrivialFunctionalExpressionUsage")
|
||||
List<ExternalTerminalType> ALL = ((Supplier<List<ExternalTerminalType>>) () -> {
|
||||
|
@ -714,5 +717,4 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
protected abstract CommandBuilder toCommand(LaunchConfiguration configuration) throws Exception;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,14 +11,61 @@ import io.xpipe.core.util.XPipeInstallation;
|
|||
|
||||
public interface KittyTerminalType extends ExternalTerminalType {
|
||||
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return true;
|
||||
public static final ExternalTerminalType KITTY_LINUX = new Linux();
|
||||
public static final ExternalTerminalType KITTY_MACOS = new MacOs();
|
||||
|
||||
private static FilePath getSocket() throws Exception {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var temp = ShellTemp.getUserSpecificTempDataDirectory(sc, null);
|
||||
sc.executeSimpleCommand(sc.getShellDialect().getMkdirsCommand(temp.toString()));
|
||||
return temp.join("xpipe_kitty");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isRecommended() {
|
||||
return true;
|
||||
private static void open(ExternalTerminalType.LaunchConfiguration configuration, CommandBuilder socketWrite)
|
||||
throws Exception {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var payload = JsonNodeFactory.instance.objectNode();
|
||||
var args = configuration.getDialectLaunchCommand().buildBaseParts(sc);
|
||||
var argsArray = payload.putArray("args");
|
||||
args.forEach(argsArray::add);
|
||||
payload.put("tab_title", configuration.getColoredTitle());
|
||||
payload.put("type", "tab");
|
||||
payload.put("logo_alpha", 0.01);
|
||||
payload.put(
|
||||
"logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString());
|
||||
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("cmd", "launch");
|
||||
json.set("payload", payload);
|
||||
json.putArray("version").add(0).add(14).add(2);
|
||||
var jsonString = json.toString();
|
||||
var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'";
|
||||
|
||||
sc.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("echo", "-en", echoString, "|")
|
||||
.add(socketWrite)
|
||||
.addFile(getSocket()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void closeInitial(CommandBuilder socketWrite) throws Exception {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var payload = JsonNodeFactory.instance.objectNode();
|
||||
payload.put("match", "not recent:0");
|
||||
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("cmd", "close-tab");
|
||||
json.set("payload", payload);
|
||||
json.putArray("version").add(0).add(14).add(2);
|
||||
var jsonString = json.toString();
|
||||
var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'";
|
||||
|
||||
sc.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("echo", "-en", echoString, "|")
|
||||
.add(socketWrite)
|
||||
.addFile(getSocket()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,55 +78,14 @@ public interface KittyTerminalType extends ExternalTerminalType {
|
|||
return "https://github.com/kovidgoyal/kitty";
|
||||
}
|
||||
|
||||
|
||||
public static final ExternalTerminalType KITTY_LINUX = new Linux();
|
||||
|
||||
public static final ExternalTerminalType KITTY_MACOS = new MacOs();
|
||||
|
||||
private static FilePath getSocket() throws Exception {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var temp = ShellTemp.getUserSpecificTempDataDirectory(sc, null);
|
||||
sc.executeSimpleCommand(sc.getShellDialect().getMkdirsCommand(temp.toString()));
|
||||
return temp.join("xpipe_kitty");
|
||||
}
|
||||
@Override
|
||||
default boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void open(ExternalTerminalType.LaunchConfiguration configuration, CommandBuilder socketWrite) throws Exception {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var payload = JsonNodeFactory.instance.objectNode();
|
||||
var args = configuration.getDialectLaunchCommand().buildBaseParts(sc);
|
||||
var argsArray = payload.putArray("args");
|
||||
args.forEach(argsArray::add);
|
||||
payload.put("tab_title",configuration.getColoredTitle());
|
||||
payload.put("type", "tab");
|
||||
payload.put("logo_alpha", 0.01);
|
||||
payload.put("logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString());
|
||||
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("cmd", "launch");
|
||||
json.set("payload", payload);
|
||||
json.putArray("version").add(0).add(14).add(2);
|
||||
var jsonString = json.toString();
|
||||
var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'";
|
||||
|
||||
sc.executeSimpleCommand(CommandBuilder.of().add("echo", "-en", echoString, "|").add(socketWrite).addFile(getSocket()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void closeInitial( CommandBuilder socketWrite) throws Exception {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var payload = JsonNodeFactory.instance.objectNode();
|
||||
payload.put("match", "not recent:0");
|
||||
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("cmd", "close-tab");
|
||||
json.set("payload", payload);
|
||||
json.putArray("version").add(0).add(14).add(2);
|
||||
var jsonString = json.toString();
|
||||
var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'";
|
||||
|
||||
sc.executeSimpleCommand(CommandBuilder.of().add("echo", "-en", echoString, "|").add(socketWrite).addFile(getSocket()));
|
||||
}
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
class Linux implements KittyTerminalType {
|
||||
|
@ -107,11 +113,19 @@ public interface KittyTerminalType extends ExternalTerminalType {
|
|||
private boolean prepare() throws Exception {
|
||||
var socket = getSocket();
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
if (sc.executeSimpleBooleanCommand("test -w " + sc.getShellDialect().fileArgument(socket))) {
|
||||
if (sc.executeSimpleBooleanCommand(
|
||||
"test -w " + sc.getShellDialect().fileArgument(socket))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sc.executeSimpleCommand(CommandBuilder.of().add("kitty").add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket(), "--detach"));
|
||||
sc.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("kitty")
|
||||
.add(
|
||||
"-o",
|
||||
"allow_remote_control=socket-only",
|
||||
"--listen-on",
|
||||
"unix:" + getSocket(),
|
||||
"--detach"));
|
||||
ThreadHelper.sleep(1500);
|
||||
return true;
|
||||
}
|
||||
|
@ -120,7 +134,9 @@ public interface KittyTerminalType extends ExternalTerminalType {
|
|||
|
||||
class MacOs extends MacOsType implements KittyTerminalType {
|
||||
|
||||
public MacOs() {super("app.kitty", "kitty");}
|
||||
public MacOs() {
|
||||
super("app.kitty", "kitty");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(LaunchConfiguration configuration) throws Exception {
|
||||
|
@ -139,11 +155,14 @@ public interface KittyTerminalType extends ExternalTerminalType {
|
|||
private boolean prepare() throws Exception {
|
||||
var socket = getSocket();
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
if (sc.executeSimpleBooleanCommand("test -w " + sc.getShellDialect().fileArgument(socket))) {
|
||||
if (sc.executeSimpleBooleanCommand(
|
||||
"test -w " + sc.getShellDialect().fileArgument(socket))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sc.executeSimpleCommand(CommandBuilder.of().add("open", "-a", "kitty.app", "--args").add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket()));
|
||||
sc.executeSimpleCommand(CommandBuilder.of()
|
||||
.add("open", "-a", "kitty.app", "--args")
|
||||
.add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket()));
|
||||
ThreadHelper.sleep(1000);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -10,52 +10,14 @@ import java.util.Optional;
|
|||
|
||||
public interface TabbyTerminalType extends ExternalTerminalType {
|
||||
|
||||
static class Windows extends ExternalTerminalType.WindowsType implements TabbyTerminalType {
|
||||
|
||||
public Windows() {
|
||||
super("app.tabby", "Tabby.exe");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
|
||||
// Tabby has a very weird handling of output, even detaching with start does not prevent it from printing
|
||||
if (configuration.getScriptDialect().equals(ShellDialects.CMD)) {
|
||||
// It also freezes with any other input than .bat files, why?
|
||||
LocalShell.getShell().executeSimpleCommand(CommandBuilder.of()
|
||||
.addFile(file.toString())
|
||||
.add("run")
|
||||
.addFile(configuration.getScriptFile())
|
||||
.discardOutput());
|
||||
}
|
||||
|
||||
// This is probably not going to work as it does not launch a bat file
|
||||
LocalShell.getShell().executeSimpleCommand(CommandBuilder.of()
|
||||
.addFile(file.toString())
|
||||
.add("run")
|
||||
.add(configuration.getDialectLaunchCommand())
|
||||
.discardOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<Path> determineInstallation() {
|
||||
var perUser = WindowsRegistry.readString(WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5",
|
||||
"InstallLocation").map(p -> p + "\\Tabby.exe").map(Path::of);
|
||||
if (perUser.isPresent()) {
|
||||
return perUser;
|
||||
}
|
||||
|
||||
var systemWide = WindowsRegistry.readString(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5",
|
||||
"InstallLocation").map(p -> p + "\\Tabby.exe").map(Path::of);
|
||||
return systemWide;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ExternalTerminalType TABBY_WINDOWS = new Windows();
|
||||
|
||||
ExternalTerminalType TABBY_MAC_OS = new MacOs();
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getWebsite() {
|
||||
return "https://tabby.sh";
|
||||
|
@ -67,13 +29,58 @@ public interface TabbyTerminalType extends ExternalTerminalType {
|
|||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
default boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static class Windows extends ExternalTerminalType.WindowsType implements TabbyTerminalType {
|
||||
|
||||
public Windows() {
|
||||
super("app.tabby", "Tabby.exe");
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return true;
|
||||
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
|
||||
// Tabby has a very weird handling of output, even detaching with start does not prevent it from printing
|
||||
if (configuration.getScriptDialect().equals(ShellDialects.CMD)) {
|
||||
// It also freezes with any other input than .bat files, why?
|
||||
LocalShell.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of()
|
||||
.addFile(file.toString())
|
||||
.add("run")
|
||||
.addFile(configuration.getScriptFile())
|
||||
.discardOutput());
|
||||
}
|
||||
|
||||
// This is probably not going to work as it does not launch a bat file
|
||||
LocalShell.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of()
|
||||
.addFile(file.toString())
|
||||
.add("run")
|
||||
.add(configuration.getDialectLaunchCommand())
|
||||
.discardOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<Path> determineInstallation() {
|
||||
var perUser = WindowsRegistry.readString(
|
||||
WindowsRegistry.HKEY_CURRENT_USER,
|
||||
"SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5",
|
||||
"InstallLocation")
|
||||
.map(p -> p + "\\Tabby.exe")
|
||||
.map(Path::of);
|
||||
if (perUser.isPresent()) {
|
||||
return perUser;
|
||||
}
|
||||
|
||||
var systemWide = WindowsRegistry.readString(
|
||||
WindowsRegistry.HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5",
|
||||
"InstallLocation")
|
||||
.map(p -> p + "\\Tabby.exe")
|
||||
.map(Path::of);
|
||||
return systemWide;
|
||||
}
|
||||
}
|
||||
|
||||
class MacOs extends MacOsType implements TabbyTerminalType {
|
||||
|
|
|
@ -10,47 +10,15 @@ import java.util.Optional;
|
|||
|
||||
public interface WezTerminalType extends ExternalTerminalType {
|
||||
|
||||
static class Windows extends WindowsType implements WezTerminalType {
|
||||
|
||||
public Windows() {
|
||||
super("app.wezterm", "wezterm-gui");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
|
||||
LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().addFile(file.toString()).add("start").add(configuration.getDialectLaunchCommand()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<Path> determineInstallation() {
|
||||
Optional<String> launcherDir;
|
||||
launcherDir = WindowsRegistry.readString(
|
||||
WindowsRegistry.HKEY_LOCAL_MACHINE,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BCF6F0DA-5B9A-408D-8562-F680AE6E1EAF}_is1",
|
||||
"InstallLocation")
|
||||
.map(p -> p + "\\wezterm-gui.exe");
|
||||
return launcherDir.map(Path::of);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Linux extends SimplePathType implements WezTerminalType {
|
||||
|
||||
public Linux() {
|
||||
super("app.wezterm", "wezterm-gui", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(LaunchConfiguration configuration) {
|
||||
return CommandBuilder.of().add("start").addFile(configuration.getScriptFile());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ExternalTerminalType WEZTERM_WINDOWS = new Windows();
|
||||
ExternalTerminalType WEZTERM_LINUX = new Linux();
|
||||
ExternalTerminalType WEZTERM_MAC_OS = new MacOs();
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getWebsite() {
|
||||
return "https://wezfurlong.org/wezterm/index.html";
|
||||
|
@ -62,13 +30,47 @@ public interface WezTerminalType extends ExternalTerminalType {
|
|||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
return false;
|
||||
default boolean supportsColoredTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static class Windows extends WindowsType implements WezTerminalType {
|
||||
|
||||
public Windows() {
|
||||
super("app.wezterm", "wezterm-gui");
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return true;
|
||||
protected void execute(Path file, LaunchConfiguration configuration) throws Exception {
|
||||
LocalShell.getShell()
|
||||
.executeSimpleCommand(CommandBuilder.of()
|
||||
.addFile(file.toString())
|
||||
.add("start")
|
||||
.add(configuration.getDialectLaunchCommand()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<Path> determineInstallation() {
|
||||
Optional<String> launcherDir;
|
||||
launcherDir = WindowsRegistry.readString(
|
||||
WindowsRegistry.HKEY_LOCAL_MACHINE,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BCF6F0DA-5B9A-408D-8562-F680AE6E1EAF}_is1",
|
||||
"InstallLocation")
|
||||
.map(p -> p + "\\wezterm-gui.exe");
|
||||
return launcherDir.map(Path::of);
|
||||
}
|
||||
}
|
||||
|
||||
static class Linux extends SimplePathType implements WezTerminalType {
|
||||
|
||||
public Linux() {
|
||||
super("app.wezterm", "wezterm-gui", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandBuilder toCommand(LaunchConfiguration configuration) {
|
||||
return CommandBuilder.of().add("start").addFile(configuration.getScriptFile());
|
||||
}
|
||||
}
|
||||
|
||||
class MacOs extends MacOsType implements WezTerminalType {
|
||||
|
|
|
@ -10,23 +10,7 @@ import java.nio.file.Path;
|
|||
|
||||
public interface WindowsTerminalType extends ExternalTerminalType {
|
||||
|
||||
@Override
|
||||
default boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final ExternalTerminalType WINDOWS_TERMINAL = new Standard();
|
||||
|
||||
public static final ExternalTerminalType WINDOWS_TERMINAL_PREVIEW = new Preview();
|
||||
|
||||
private static CommandBuilder toCommand(ExternalTerminalType.LaunchConfiguration configuration) throws Exception {
|
||||
|
@ -48,9 +32,26 @@ public interface WindowsTerminalType extends ExternalTerminalType {
|
|||
return cmd.add("--title").addQuoted(fixedName).add(toExec);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsTabs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isRecommended() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsColoredTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
class Standard extends SimplePathType implements WindowsTerminalType {
|
||||
|
||||
public Standard() {super("app.windowsTerminal", "wt.exe", false);}
|
||||
public Standard() {
|
||||
super("app.windowsTerminal", "wt.exe", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWebsite() {
|
||||
|
|
|
@ -68,7 +68,9 @@ public class DesktopShortcuts {
|
|||
.createTextFileWriteCommand(pc, "APPL????", base + "/Contents/PkgInfo")
|
||||
.execute();
|
||||
pc.getShellDialect()
|
||||
.createTextFileWriteCommand(pc, """
|
||||
.createTextFileWriteCommand(
|
||||
pc,
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
|
@ -77,7 +79,8 @@ public class DesktopShortcuts {
|
|||
<string>icon.icns</string>
|
||||
</dict>
|
||||
</plist>
|
||||
""", base + "/Contents/Info.plist")
|
||||
""",
|
||||
base + "/Contents/Info.plist")
|
||||
.execute();
|
||||
pc.executeSimpleCommand("cp \"" + icon + "\" \"" + base + "/Contents/Resources/icon.icns\"");
|
||||
}
|
||||
|
|
|
@ -40,7 +40,19 @@ public class InputHelper {
|
|||
public static void onNavigationInput(EventTarget target, Consumer<Boolean> r) {
|
||||
target.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
var c = event.getCode();
|
||||
var list = List.of(KeyCode.LEFT, KeyCode.RIGHT, KeyCode.UP, KeyCode.DOWN, KeyCode.SPACE, KeyCode.ENTER, KeyCode.SHIFT, KeyCode.TAB, KeyCode.NUMPAD2, KeyCode.NUMPAD4, KeyCode.NUMPAD6, KeyCode.NUMPAD8);
|
||||
var list = List.of(
|
||||
KeyCode.LEFT,
|
||||
KeyCode.RIGHT,
|
||||
KeyCode.UP,
|
||||
KeyCode.DOWN,
|
||||
KeyCode.SPACE,
|
||||
KeyCode.ENTER,
|
||||
KeyCode.SHIFT,
|
||||
KeyCode.TAB,
|
||||
KeyCode.NUMPAD2,
|
||||
KeyCode.NUMPAD4,
|
||||
KeyCode.NUMPAD6,
|
||||
KeyCode.NUMPAD8);
|
||||
r.accept(list.stream().anyMatch(keyCode -> keyCode == c));
|
||||
});
|
||||
target.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
|
||||
|
|
|
@ -41,6 +41,5 @@ public abstract class LicenseProvider {
|
|||
.findFirst()
|
||||
.orElseThrow(() -> ExtensionException.corrupt("Missing license provider"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,15 @@ public enum PlatformState {
|
|||
|
||||
public static void teardown() {
|
||||
// This is bad and can get sometimes stuck
|
||||
// PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
// try {
|
||||
// // Fix to preserve clipboard contents after shutdown
|
||||
// var string = Clipboard.getSystemClipboard().getString();
|
||||
// var s = new StringSelection(string);
|
||||
// Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s);
|
||||
// } catch (IllegalStateException ignored) {
|
||||
// }
|
||||
// });
|
||||
// PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
// try {
|
||||
// // Fix to preserve clipboard contents after shutdown
|
||||
// var string = Clipboard.getSystemClipboard().getString();
|
||||
// var s = new StringSelection(string);
|
||||
// Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s);
|
||||
// } catch (IllegalStateException ignored) {
|
||||
// }
|
||||
// });
|
||||
|
||||
Platform.exit();
|
||||
setCurrent(PlatformState.EXITED);
|
||||
|
|
|
@ -13,6 +13,8 @@ import java.util.stream.Collectors;
|
|||
@Value
|
||||
public class RdpConfig {
|
||||
|
||||
Map<String, TypedValue> content;
|
||||
|
||||
public static RdpConfig parseFile(String file) throws IOException {
|
||||
var content = Files.readString(Path.of(file));
|
||||
return parseContent(content);
|
||||
|
@ -30,7 +32,6 @@ public class RdpConfig {
|
|||
map.put(split[0].trim(), new RdpConfig.TypedValue("s", split[1].trim()));
|
||||
}
|
||||
|
||||
|
||||
if (split.length == 3) {
|
||||
map.put(split[0].trim(), new RdpConfig.TypedValue(split[1].trim(), split[2].trim()));
|
||||
}
|
||||
|
@ -38,14 +39,6 @@ public class RdpConfig {
|
|||
return new RdpConfig(map);
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class TypedValue {
|
||||
String type;
|
||||
String value;
|
||||
}
|
||||
|
||||
Map<String, TypedValue> content;
|
||||
|
||||
public RdpConfig overlay(Map<String, TypedValue> override) {
|
||||
var newMap = new LinkedHashMap<>(content);
|
||||
newMap.putAll(override);
|
||||
|
@ -53,12 +46,21 @@ public class RdpConfig {
|
|||
}
|
||||
|
||||
public String toString() {
|
||||
return content.entrySet().stream().map(e -> {
|
||||
return e.getKey() + ":" + e.getValue().getType() + ":" + e.getValue().getValue();
|
||||
}).collect(Collectors.joining("\n"));
|
||||
return content.entrySet().stream()
|
||||
.map(e -> {
|
||||
return e.getKey() + ":" + e.getValue().getType() + ":"
|
||||
+ e.getValue().getValue();
|
||||
})
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public Optional<TypedValue> get(String key) {
|
||||
return Optional.ofNullable(content.get(key));
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class TypedValue {
|
||||
String type;
|
||||
String value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,8 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static FilePath createExecScript(ShellDialect type, ShellControl processControl, FilePath file, String content) {
|
||||
public static FilePath createExecScript(
|
||||
ShellDialect type, ShellControl processControl, FilePath file, String content) {
|
||||
content = type.prepareScriptContent(content);
|
||||
|
||||
TrackEvent.withTrace("Writing exec script")
|
||||
|
|
|
@ -59,7 +59,8 @@ public class ShellTemp {
|
|||
var d = proc.getShellDialect();
|
||||
|
||||
var systemTemp = proc.getSystemTemporaryDirectory();
|
||||
if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck() || !checkDirectoryPermissions(proc, systemTemp.toString())) {
|
||||
if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck()
|
||||
|| !checkDirectoryPermissions(proc, systemTemp.toString())) {
|
||||
throw ErrorEvent.expected(new IOException("No permissions to access %s".formatted(systemTemp)));
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ public abstract class StringSource {
|
|||
try (var sc = host.control().start()) {
|
||||
var path = file.toAbsoluteFilePath(sc);
|
||||
if (!sc.getShellDialect().createFileExistsCommand(sc, path).executeAndCheck()) {
|
||||
throw ErrorEvent.expected(
|
||||
new IllegalArgumentException("File " + path + " does not exist"));
|
||||
throw ErrorEvent.expected(new IllegalArgumentException("File " + path + " does not exist"));
|
||||
}
|
||||
|
||||
var abs = file.toAbsoluteFilePath(sc);
|
||||
|
|
|
@ -18,14 +18,23 @@ import java.util.UUID;
|
|||
|
||||
public class TerminalLauncher {
|
||||
|
||||
public static void openDirect(String title, FailableFunction<ShellControl,String, Exception> command) throws Exception {
|
||||
public static void openDirect(String title, FailableFunction<ShellControl, String, Exception> command)
|
||||
throws Exception {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var type = AppPrefs.get().terminalType().getValue();
|
||||
if (type == null) {
|
||||
throw ErrorEvent.expected(new IllegalStateException(AppI18n.get("noTerminalSet")));
|
||||
}
|
||||
var script = ScriptHelper.constructTerminalInitFile(sc.getShellDialect(), sc, ignored -> null, List.of(),
|
||||
command.apply(sc), new TerminalInitScriptConfig(title, type.shouldClear() && AppPrefs.get().clearTerminalOnInit().get()));
|
||||
var script = ScriptHelper.constructTerminalInitFile(
|
||||
sc.getShellDialect(),
|
||||
sc,
|
||||
ignored -> null,
|
||||
List.of(),
|
||||
command.apply(sc),
|
||||
new TerminalInitScriptConfig(
|
||||
title,
|
||||
type.shouldClear()
|
||||
&& AppPrefs.get().clearTerminalOnInit().get()));
|
||||
var config = new ExternalTerminalType.LaunchConfiguration(null, title, title, script, sc.getShellDialect());
|
||||
type.launch(config);
|
||||
}
|
||||
|
|
|
@ -15,18 +15,6 @@ import java.lang.reflect.Method;
|
|||
@Getter
|
||||
public class WindowControl {
|
||||
|
||||
public interface DwmSupport extends Library {
|
||||
|
||||
DwmSupport INSTANCE = Native.load("dwmapi", DwmSupport.class);
|
||||
|
||||
WinNT.HRESULT DwmSetWindowAttribute(
|
||||
WinDef.HWND hwnd,
|
||||
int dwAttribute,
|
||||
PointerType pvAttribute,
|
||||
int cbAttribute
|
||||
);
|
||||
}
|
||||
|
||||
private final WinDef.HWND windowHandle;
|
||||
|
||||
public WindowControl(Window stage) throws Exception {
|
||||
|
@ -48,16 +36,20 @@ public class WindowControl {
|
|||
}
|
||||
|
||||
public void move(int x, int y, int w, int h) {
|
||||
User32.INSTANCE.SetWindowPos(windowHandle, new WinDef.HWND(), x,y,w,h, 0);
|
||||
User32.INSTANCE.SetWindowPos(windowHandle, new WinDef.HWND(), x, y, w, h, 0);
|
||||
}
|
||||
|
||||
public void setWindowAttribute(int attribute, boolean attributeValue) {
|
||||
DwmSupport.INSTANCE.DwmSetWindowAttribute(
|
||||
windowHandle,
|
||||
attribute,
|
||||
new WinDef.BOOLByReference(new WinDef.BOOL(attributeValue)),
|
||||
WinDef.BOOL.SIZE
|
||||
);
|
||||
windowHandle, attribute, new WinDef.BOOLByReference(new WinDef.BOOL(attributeValue)), WinDef.BOOL.SIZE);
|
||||
User32.INSTANCE.UpdateWindow(windowHandle);
|
||||
}
|
||||
|
||||
public interface DwmSupport extends Library {
|
||||
|
||||
DwmSupport INSTANCE = Native.load("dwmapi", DwmSupport.class);
|
||||
|
||||
WinNT.HRESULT DwmSetWindowAttribute(
|
||||
WinDef.HWND hwnd, int dwAttribute, PointerType pvAttribute, int cbAttribute);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,7 +117,8 @@ open module io.xpipe.app {
|
|||
provides Module with
|
||||
StorageJacksonModule;
|
||||
provides ModuleLayerLoader with
|
||||
MessageExchangeImpls.Loader, DataStoreProviders.Loader,
|
||||
MessageExchangeImpls.Loader,
|
||||
DataStoreProviders.Loader,
|
||||
ActionProvider.Loader,
|
||||
PrefsProvider.Loader,
|
||||
BrowserAction.Loader,
|
||||
|
|
|
@ -5,8 +5,7 @@ import java.util.function.Consumer;
|
|||
|
||||
public interface ModuleLayerLoader {
|
||||
|
||||
static void loadAll(
|
||||
ModuleLayer layer, Consumer<Throwable> errorHandler) {
|
||||
static void loadAll(ModuleLayer layer, Consumer<Throwable> errorHandler) {
|
||||
ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> {
|
||||
var instance = moduleLayerLoaderProvider.get();
|
||||
try {
|
||||
|
@ -20,5 +19,4 @@ public interface ModuleLayerLoader {
|
|||
default void init(ModuleLayer layer) {}
|
||||
|
||||
default void reset() {}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.Node;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.BranchAction;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.core.process.CommandBuilder;
|
||||
import io.xpipe.core.process.OsType;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.BrowserClipboard;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.Node;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
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.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.ClipboardHelper;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
@ -133,9 +133,8 @@ public class CopyPathAction implements BrowserAction, BranchAction {
|
|||
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
if (entries.size() == 1) {
|
||||
return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis(
|
||||
FileNames.getFileName(entries.getFirst()
|
||||
.getRawFileEntry()
|
||||
.getPath()),
|
||||
FileNames.getFileName(
|
||||
entries.getFirst().getRawFileEntry().getPath()),
|
||||
50));
|
||||
}
|
||||
|
||||
|
@ -156,9 +155,8 @@ public class CopyPathAction implements BrowserAction, BranchAction {
|
|||
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
if (entries.size() == 1) {
|
||||
return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis(
|
||||
FileNames.getFileName(entries.getFirst()
|
||||
.getRawFileEntry()
|
||||
.getPath()),
|
||||
FileNames.getFileName(
|
||||
entries.getFirst().getRawFileEntry().getPath()),
|
||||
50));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserAlerts;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.file.FileSystemHelper;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
@ -46,7 +46,9 @@ public class DeleteAction implements LeafAction {
|
|||
|
||||
@Override
|
||||
public ObservableValue<String> getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return AppI18n.observable("deleteFile",entries.stream()
|
||||
return AppI18n.observable(
|
||||
"deleteFile",
|
||||
entries.stream()
|
||||
.allMatch(browserEntry ->
|
||||
browserEntry.getRawFileEntry().getKind() == FileKind.LINK)
|
||||
? " link"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.file.FileSystemHelper;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.BrowserAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.BrowserAction;
|
||||
import io.xpipe.app.browser.icon.BrowserIconFileType;
|
||||
import io.xpipe.app.browser.icon.BrowserIcons;
|
||||
import javafx.scene.Node;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.Node;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.BrowserActionFormatter;
|
||||
import io.xpipe.app.browser.action.MultiExecuteAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.icon.BrowserIconFileType;
|
||||
import io.xpipe.core.process.CommandBuilder;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
@ -31,7 +31,9 @@ public class JarAction extends MultiExecuteAction implements JavaAction, FileTyp
|
|||
|
||||
@Override
|
||||
protected CommandBuilder createCommand(ShellControl sc, OpenFileSystemModel model, BrowserEntry entry) {
|
||||
return CommandBuilder.of().add("java", "-jar").addFile(entry.getRawFileEntry().getPath());
|
||||
return CommandBuilder.of()
|
||||
.add("java", "-jar")
|
||||
.addFile(entry.getRawFileEntry().getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.BrowserActionFormatter;
|
||||
import io.xpipe.app.browser.action.ToFileCommandAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.icon.BrowserIconFileType;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.BranchAction;
|
||||
import io.xpipe.app.browser.action.BrowserAction;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.icon.BrowserIcons;
|
||||
import io.xpipe.app.comp.base.ModalOverlayComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.session.BrowserSessionModel;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
@ -17,7 +17,8 @@ public class OpenDirectoryInNewTabAction implements LeafAction {
|
|||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
if (model.getBrowserModel() instanceof BrowserSessionModel bm) {
|
||||
bm.openFileSystemAsync(model.getEntry(), m -> entries.getFirst().getRawFileEntry().getPath(), null);
|
||||
bm.openFileSystemAsync(
|
||||
model.getEntry(), m -> entries.getFirst().getRawFileEntry().getPath(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,8 @@ public class OpenDirectoryInNewTabAction implements LeafAction {
|
|||
|
||||
@Override
|
||||
public boolean isApplicable(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return model.getBrowserModel() instanceof BrowserSessionModel && entries.size() == 1
|
||||
return model.getBrowserModel() instanceof BrowserSessionModel
|
||||
&& entries.size() == 1
|
||||
&& entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.core.process.OsType;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.ext.base.browser;
|
||||
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.browser.file.BrowserEntry;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.process.OsType;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue