[stage]
|
@ -115,7 +115,6 @@ Alternatively, you can also use your favorite package manager (if supported):
|
||||||
- [choco](https://community.chocolatey.org/packages/xpipe): `choco install xpipe`
|
- [choco](https://community.chocolatey.org/packages/xpipe): `choco install xpipe`
|
||||||
- [AUR package](https://aur.archlinux.org/packages/xpipe): `yay -S xpipe`
|
- [AUR package](https://aur.archlinux.org/packages/xpipe): `yay -S xpipe`
|
||||||
- [Homebrew](https://github.com/xpipe-io/homebrew-tap): `brew install --cask xpipe-io/tap/xpipe`
|
- [Homebrew](https://github.com/xpipe-io/homebrew-tap): `brew install --cask xpipe-io/tap/xpipe`
|
||||||
- [nixpkg](https://github.com/xpipe-io/nixpkg): You can install XPipe by following the linked repository instructions
|
|
||||||
|
|
||||||
## Open source model
|
## Open source model
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class BrowserWelcomeComp extends SimpleComp {
|
||||||
var listBox = new ListBoxViewComp<>(list, list, e -> {
|
var listBox = new ListBoxViewComp<>(list, list, e -> {
|
||||||
var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid());
|
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, 50, 40);
|
var view = PrettyImageHelper.ofFixedSquare(graphic, 45);
|
||||||
view.padding(new Insets(2, 8, 2, 8));
|
view.padding(new Insets(2, 8, 2, 8));
|
||||||
var content =
|
var content =
|
||||||
JfxHelper.createNamedEntry(DataStorage.get().getStoreDisplayName(entry.get()), e.getPath(), graphic);
|
JfxHelper.createNamedEntry(DataStorage.get().getStoreDisplayName(entry.get()), e.getPath(), graphic);
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class FileSystemHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
var shell = model.getFileSystem().getShell();
|
var shell = model.getFileSystem().getShell();
|
||||||
if (shell.isEmpty() || !shell.get().isRunning()) {
|
if (shell.isEmpty()) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,9 +131,6 @@ public final class OpenFileSystemModel {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start shell in case we exited
|
|
||||||
getFileSystem().getShell().orElseThrow().start();
|
|
||||||
|
|
||||||
// Fix common issues with paths
|
// Fix common issues with paths
|
||||||
var adjustedPath = FileSystemHelper.adjustPath(this, path);
|
var adjustedPath = FileSystemHelper.adjustPath(this, path);
|
||||||
if (!Objects.equals(path, adjustedPath)) {
|
if (!Objects.equals(path, adjustedPath)) {
|
||||||
|
|
|
@ -29,8 +29,6 @@ public interface LeafAction extends BrowserAction {
|
||||||
|
|
||||||
ThreadHelper.runFailableAsync(() -> {
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
BooleanScope.execute(model.getBusy(), () -> {
|
BooleanScope.execute(model.getBusy(), () -> {
|
||||||
// Start shell in case we exited
|
|
||||||
model.getFileSystem().getShell().orElseThrow().start();
|
|
||||||
execute(model, selected);
|
execute(model, selected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -66,8 +64,6 @@ public interface LeafAction extends BrowserAction {
|
||||||
mi.setOnAction(event -> {
|
mi.setOnAction(event -> {
|
||||||
ThreadHelper.runFailableAsync(() -> {
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
BooleanScope.execute(model.getBusy(), () -> {
|
BooleanScope.execute(model.getBusy(), () -> {
|
||||||
// Start shell in case we exited
|
|
||||||
model.getFileSystem().getShell().orElseThrow().start();
|
|
||||||
execute(model, selected);
|
execute(model, selected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class OsLogoComp extends SimpleComp {
|
||||||
var hide = BindingsHelper.map(img, s -> s != null);
|
var hide = BindingsHelper.map(img, s -> s != null);
|
||||||
return new StackComp(List.of(
|
return new StackComp(List.of(
|
||||||
new SystemStateComp(state).hide(hide),
|
new SystemStateComp(state).hide(hide),
|
||||||
PrettyImageHelper.ofRasterized(img, 24, 24).visible(hide)))
|
PrettyImageHelper.ofSvg(img, 24, 24).visible(hide)))
|
||||||
.createRegion();
|
.createRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,9 +66,8 @@ public class OsLogoComp extends SimpleComp {
|
||||||
if (ICONS.isEmpty()) {
|
if (ICONS.isEmpty()) {
|
||||||
AppResources.with(AppResources.XPIPE_MODULE, "img/os", file -> {
|
AppResources.with(AppResources.XPIPE_MODULE, "img/os", file -> {
|
||||||
try (var list = Files.list(file)) {
|
try (var list = Files.list(file)) {
|
||||||
list.filter(path -> path.toString().endsWith(".svg") && !path.toString().endsWith(LINUX_DEFAULT))
|
list.filter(path -> !path.toString().endsWith(LINUX_DEFAULT)).map(path -> FileNames.getFileName(path.toString())).forEach(path -> {
|
||||||
.map(path -> FileNames.getFileName(path.toString())).forEach(path -> {
|
var base = FileNames.getBaseName(path).replace("-dark", "") + ".svg";
|
||||||
var base = FileNames.getBaseName(path).replace("-dark", "") + "-24.png";
|
|
||||||
ICONS.put(FileNames.getBaseName(base).split("-")[0], "os/" + base);
|
ICONS.put(FileNames.getBaseName(base).split("-")[0], "os/" + base);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class DenseStoreEntryComp extends StoreEntryComp {
|
||||||
}, grid.widthProperty()));
|
}, grid.widthProperty()));
|
||||||
|
|
||||||
if (showIcon) {
|
if (showIcon) {
|
||||||
var storeIcon = createIcon(30, 24);
|
var storeIcon = createIcon(30, 25);
|
||||||
grid.getColumnConstraints().add(new ColumnConstraints(46));
|
grid.getColumnConstraints().add(new ColumnConstraints(46));
|
||||||
grid.add(storeIcon, 0, 0);
|
grid.add(storeIcon, 0, 0);
|
||||||
GridPane.setHalignment(storeIcon, HPos.CENTER);
|
GridPane.setHalignment(storeIcon, HPos.CENTER);
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
package io.xpipe.app.comp.store;
|
package io.xpipe.app.comp.store;
|
||||||
|
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.ext.DataStoreProvider;
|
import io.xpipe.app.ext.DataStoreProvider;
|
||||||
import io.xpipe.app.ext.DataStoreProviders;
|
import io.xpipe.app.ext.DataStoreProviders;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.CompStructure;
|
import io.xpipe.app.fxcomps.CompStructure;
|
||||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
|
import io.xpipe.app.util.CustomComboBoxBuilder;
|
||||||
import io.xpipe.app.util.JfxHelper;
|
import io.xpipe.app.util.JfxHelper;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.ListCell;
|
|
||||||
import javafx.scene.input.KeyCode;
|
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
@ -18,23 +19,27 @@ import lombok.experimental.FieldDefaults;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class DataStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<DataStoreProvider>>> {
|
public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>>> {
|
||||||
|
|
||||||
Predicate<DataStoreProvider> filter;
|
Predicate<DataStoreProvider> filter;
|
||||||
Property<DataStoreProvider> provider;
|
Property<DataStoreProvider> provider;
|
||||||
boolean staticDisplay;
|
boolean staticDisplay;
|
||||||
|
|
||||||
|
private Region createDefaultNode() {
|
||||||
|
return JfxHelper.createNamedEntry(
|
||||||
|
AppI18n.get("selectType"), AppI18n.get("selectTypeDescription"), "connection_icon.svg");
|
||||||
|
}
|
||||||
|
|
||||||
private List<DataStoreProvider> getProviders() {
|
private List<DataStoreProvider> getProviders() {
|
||||||
return DataStoreProviders.getAll().stream().filter(filter).toList();
|
return DataStoreProviders.getAll().stream().filter(filter).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Region createGraphic(DataStoreProvider provider) {
|
private Region createGraphic(DataStoreProvider provider) {
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
return null;
|
return createDefaultNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
var graphic = provider.getDisplayIconFileName(null);
|
var graphic = provider.getDisplayIconFileName(null);
|
||||||
|
@ -42,40 +47,20 @@ public class DataStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Dat
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompStructure<ComboBox<DataStoreProvider>> createBase() {
|
public CompStructure<ComboBox<Node>> createBase() {
|
||||||
Supplier<ListCell<DataStoreProvider>> cellFactory = () -> new ListCell<>() {
|
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, createDefaultNode(), v -> true);
|
||||||
@Override
|
comboBox.setAccessibleNames(dataStoreProvider -> dataStoreProvider.getDisplayName());
|
||||||
protected void updateItem(DataStoreProvider item, boolean empty) {
|
|
||||||
super.updateItem(item, empty);
|
|
||||||
setGraphic(createGraphic(item));
|
|
||||||
setAccessibleText(item != null ? item.getDisplayName() : null);
|
|
||||||
setAccessibleHelp(item != null ? item.getDisplayDescription() : null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var cb = new ComboBox<DataStoreProvider>();
|
|
||||||
cb.setCellFactory(param -> {
|
|
||||||
return cellFactory.get();
|
|
||||||
});
|
|
||||||
cb.setButtonCell(cellFactory.get());
|
|
||||||
var l = getProviders().stream()
|
var l = getProviders().stream()
|
||||||
.filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.getCreationCategory() != null || staticDisplay)
|
.filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.getCreationCategory() != null || staticDisplay).toList();
|
||||||
.toList();
|
l
|
||||||
l.forEach(dataStoreProvider -> cb.getItems().add(dataStoreProvider));
|
.forEach(comboBox::add);
|
||||||
if (provider.getValue() == null) {
|
if (l.size() == 1) {
|
||||||
provider.setValue(l.getFirst());
|
provider.setValue(l.get(0));
|
||||||
}
|
}
|
||||||
cb.setValue(provider.getValue());
|
ComboBox<Node> cb = comboBox.build();
|
||||||
provider.bind(cb.valueProperty());
|
cb.getStyleClass().add("data-source-type");
|
||||||
cb.getStyleClass().add("choice-comp");
|
cb.getStyleClass().add("choice-comp");
|
||||||
cb.setAccessibleText("Choose connection type");
|
cb.setAccessibleText("Choose connection type");
|
||||||
cb.setOnKeyPressed(event -> {
|
|
||||||
if (!event.getCode().equals(KeyCode.ENTER)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb.show();
|
|
||||||
event.consume();
|
|
||||||
});
|
|
||||||
return new SimpleCompStructure<>(cb);
|
return new SimpleCompStructure<>(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -276,7 +276,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
var layout = new BorderPane();
|
var layout = new BorderPane();
|
||||||
layout.getStyleClass().add("store-creator");
|
layout.getStyleClass().add("store-creator");
|
||||||
layout.setPadding(new Insets(20));
|
layout.setPadding(new Insets(20));
|
||||||
var providerChoice = new DataStoreProviderChoiceComp(filter, provider, staticDisplay);
|
var providerChoice = new DsStoreProviderChoiceComp(filter, provider, staticDisplay);
|
||||||
if (staticDisplay) {
|
if (staticDisplay) {
|
||||||
providerChoice.apply(struc -> struc.get().setDisable(true));
|
providerChoice.apply(struc -> struc.get().setDisable(true));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ public class StandardStoreEntryComp extends StoreEntryComp {
|
||||||
grid.setHgap(7);
|
grid.setHgap(7);
|
||||||
grid.setVgap(0);
|
grid.setVgap(0);
|
||||||
|
|
||||||
var storeIcon = createIcon(50, 40);
|
var storeIcon = createIcon(50, 39);
|
||||||
grid.add(storeIcon, 0, 0, 1, 2);
|
grid.add(storeIcon, 0, 0, 1, 2);
|
||||||
grid.getColumnConstraints().add(new ColumnConstraints(66));
|
grid.getColumnConstraints().add(new ColumnConstraints(66));
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,7 @@ package io.xpipe.app.comp.store;
|
||||||
import io.xpipe.app.core.AppI18n;
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.ext.DataStoreProvider;
|
import io.xpipe.app.ext.DataStoreProvider;
|
||||||
import io.xpipe.app.ext.DataStoreProviders;
|
import io.xpipe.app.ext.DataStoreProviders;
|
||||||
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
|
|
||||||
import io.xpipe.app.util.ScanAlert;
|
import io.xpipe.app.util.ScanAlert;
|
||||||
import javafx.scene.control.Menu;
|
|
||||||
import javafx.scene.control.MenuButton;
|
import javafx.scene.control.MenuButton;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.control.SeparatorMenuItem;
|
import javafx.scene.control.SeparatorMenuItem;
|
||||||
|
@ -14,6 +12,7 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
public class StoreCreationMenu {
|
public class StoreCreationMenu {
|
||||||
|
|
||||||
public static void addButtons(MenuButton menu) {
|
public static void addButtons(MenuButton menu) {
|
||||||
|
{
|
||||||
var automatically = new MenuItem();
|
var automatically = new MenuItem();
|
||||||
automatically.setGraphic(new FontIcon("mdi2e-eye-plus-outline"));
|
automatically.setGraphic(new FontIcon("mdi2e-eye-plus-outline"));
|
||||||
automatically.textProperty().bind(AppI18n.observable("addAutomatically"));
|
automatically.textProperty().bind(AppI18n.observable("addAutomatically"));
|
||||||
|
@ -23,62 +22,74 @@ public class StoreCreationMenu {
|
||||||
});
|
});
|
||||||
menu.getItems().add(automatically);
|
menu.getItems().add(automatically);
|
||||||
menu.getItems().add(new SeparatorMenuItem());
|
menu.getItems().add(new SeparatorMenuItem());
|
||||||
|
|
||||||
menu.getItems().add(category("addHost", "mdi2h-home-plus",
|
|
||||||
DataStoreProvider.CreationCategory.HOST, "ssh"));
|
|
||||||
|
|
||||||
menu.getItems().add(category("addShell", "mdi2t-text-box-multiple",
|
|
||||||
DataStoreProvider.CreationCategory.SHELL, null));
|
|
||||||
|
|
||||||
menu.getItems().add(category("addScript", "mdi2s-script-text-outline",
|
|
||||||
DataStoreProvider.CreationCategory.SCRIPT, "script"));
|
|
||||||
|
|
||||||
menu.getItems().add(category("addCommand", "mdi2c-code-greater-than",
|
|
||||||
DataStoreProvider.CreationCategory.COMMAND, "cmd"));
|
|
||||||
|
|
||||||
menu.getItems().add(category("addTunnel", "mdi2v-vector-polyline-plus",
|
|
||||||
DataStoreProvider.CreationCategory.TUNNEL, null));
|
|
||||||
|
|
||||||
menu.getItems().add(category("addDatabase", "mdi2d-database-plus",
|
|
||||||
DataStoreProvider.CreationCategory.DATABASE, null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MenuItem category(String name, String graphic, DataStoreProvider.CreationCategory category, String defaultProvider) {
|
{
|
||||||
var sub = DataStoreProviders.getAll().stream().filter(dataStoreProvider -> category.equals(dataStoreProvider.getCreationCategory())).toList();
|
var host = new MenuItem();
|
||||||
if (sub.size() < 2) {
|
host.setGraphic(new FontIcon("mdi2h-home-plus"));
|
||||||
var item = new MenuItem();
|
host.textProperty().bind(AppI18n.observable("addHost"));
|
||||||
item.setGraphic(new FontIcon(graphic));
|
host.setOnAction(event -> {
|
||||||
item.textProperty().bind(AppI18n.observable(name));
|
GuiDsStoreCreator.showCreation(DataStoreProviders.byName("ssh").orElseThrow(),
|
||||||
item.setOnAction(event -> {
|
v -> DataStoreProvider.CreationCategory.HOST.equals(v.getCreationCategory()));
|
||||||
GuiDsStoreCreator.showCreation(defaultProvider != null ? DataStoreProviders.byName(defaultProvider).orElseThrow() : null,
|
|
||||||
v -> category.equals(v.getCreationCategory()));
|
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
return item;
|
menu.getItems().add(host);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
var menu = new Menu();
|
var shell = new MenuItem();
|
||||||
menu.setGraphic(new FontIcon(graphic));
|
shell.setGraphic(new FontIcon("mdi2t-text-box-multiple"));
|
||||||
menu.textProperty().bind(AppI18n.observable(name));
|
shell.textProperty().bind(AppI18n.observable("addShell"));
|
||||||
menu.setOnAction(event -> {
|
shell.setOnAction(event -> {
|
||||||
if (event.getTarget() != menu) {
|
GuiDsStoreCreator.showCreation(null,
|
||||||
return;
|
v -> DataStoreProvider.CreationCategory.SHELL.equals(v.getCreationCategory()));
|
||||||
}
|
|
||||||
|
|
||||||
GuiDsStoreCreator.showCreation(defaultProvider != null ? DataStoreProviders.byName(defaultProvider).orElseThrow() : null,
|
|
||||||
v -> category.equals(v.getCreationCategory()));
|
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
sub.forEach(dataStoreProvider -> {
|
menu.getItems().add(shell);
|
||||||
var item = new MenuItem(dataStoreProvider.getDisplayName());
|
}
|
||||||
item.setGraphic(PrettyImageHelper.ofFixedSmallSquare(dataStoreProvider.getDisplayIconFileName(null)).createRegion());
|
{
|
||||||
item.setOnAction(event -> {
|
var cmd = new MenuItem();
|
||||||
GuiDsStoreCreator.showCreation(dataStoreProvider,
|
cmd.setGraphic(new FontIcon("mdi2c-code-greater-than"));
|
||||||
v -> category.equals(v.getCreationCategory()));
|
cmd.textProperty().bind(AppI18n.observable("addCommand"));
|
||||||
|
cmd.setOnAction(event -> {
|
||||||
|
GuiDsStoreCreator.showCreation(DataStoreProviders.byName("cmd").orElseThrow(),
|
||||||
|
v -> DataStoreProvider.CreationCategory.COMMAND.equals(v.getCreationCategory()));
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
menu.getItems().add(item);
|
menu.getItems().add(cmd);
|
||||||
});
|
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
var db = new MenuItem();
|
||||||
|
db.setGraphic(new FontIcon("mdi2d-database-plus"));
|
||||||
|
db.textProperty().bind(AppI18n.observable("addDatabase"));
|
||||||
|
db.setOnAction(event -> {
|
||||||
|
GuiDsStoreCreator.showCreation(null,
|
||||||
|
v -> DataStoreProvider.CreationCategory.DATABASE.equals(v.getCreationCategory()));
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
menu.getItems().add(db);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var tunnel = new MenuItem();
|
||||||
|
tunnel.setGraphic(new FontIcon("mdi2v-vector-polyline-plus"));
|
||||||
|
tunnel.textProperty().bind(AppI18n.observable("addTunnel"));
|
||||||
|
tunnel.setOnAction(event -> {
|
||||||
|
GuiDsStoreCreator.showCreation(null,
|
||||||
|
v -> DataStoreProvider.CreationCategory.TUNNEL.equals(v.getCreationCategory()));
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
menu.getItems().add(tunnel);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var script = new MenuItem();
|
||||||
|
script.setGraphic(new FontIcon("mdi2s-script-text-outline"));
|
||||||
|
script.textProperty().bind(AppI18n.observable("addScript"));
|
||||||
|
script.setOnAction(event -> {
|
||||||
|
GuiDsStoreCreator.showCreation(DataStoreProviders.byName("script").orElseThrow(),
|
||||||
|
v -> DataStoreProvider.CreationCategory.SCRIPT.equals(v.getCreationCategory()));
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
menu.getItems().add(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||||
: wrapper.getEntry()
|
: wrapper.getEntry()
|
||||||
.getProvider()
|
.getProvider()
|
||||||
.getDisplayIconFileName(wrapper.getEntry().getStore());
|
.getDisplayIconFileName(wrapper.getEntry().getStore());
|
||||||
var imageComp = PrettyImageHelper.ofFixedSize(img, w, h);
|
var imageComp = PrettyImageHelper.ofFixed(img, w, h);
|
||||||
var storeIcon = imageComp.createRegion();
|
var storeIcon = imageComp.createRegion();
|
||||||
if (wrapper.getValidity().getValue().isUsable()) {
|
if (wrapper.getValidity().getValue().isUsable()) {
|
||||||
new FancyTooltipAugment<>(new SimpleStringProperty(
|
new FancyTooltipAugment<>(new SimpleStringProperty(
|
||||||
|
|
|
@ -124,10 +124,6 @@ public class AppTheme {
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
if (AppMainWindow.getInstance() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var window = AppMainWindow.getInstance().getStage();
|
var window = AppMainWindow.getInstance().getStage();
|
||||||
var scene = window.getScene();
|
var scene = window.getScene();
|
||||||
Pane root = (Pane) scene.getRoot();
|
Pane root = (Pane) scene.getRoot();
|
||||||
|
|
|
@ -269,11 +269,6 @@ public class AppWindowHelper {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should not happen but on weird Linux systems nothing is impossible
|
|
||||||
if (w < 0 || h < 0) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed ? Optional.of(new Rectangle2D(x, y, w, h)) : Optional.empty();
|
return changed ? Optional.of(new Rectangle2D(x, y, w, h)) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package io.xpipe.app.ext;
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
@ -16,6 +17,7 @@ public class DataStoreProviders {
|
||||||
if (ALL == null) {
|
if (ALL == null) {
|
||||||
ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream()
|
ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream()
|
||||||
.map(ServiceLoader.Provider::get)
|
.map(ServiceLoader.Provider::get)
|
||||||
|
.sorted(Comparator.comparing(DataStoreProvider::getId))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
ALL.removeIf(p -> {
|
ALL.removeIf(p -> {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package io.xpipe.app.fxcomps.impl;
|
||||||
|
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
|
import io.xpipe.app.util.CustomComboBoxBuilder;
|
||||||
|
import io.xpipe.core.charsetter.StreamCharset;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
public class CharsetChoiceComp extends SimpleComp {
|
||||||
|
|
||||||
|
private final Property<StreamCharset> charset;
|
||||||
|
|
||||||
|
public CharsetChoiceComp(Property<StreamCharset> charset) {
|
||||||
|
this.charset = charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var builder = new CustomComboBoxBuilder<>(
|
||||||
|
charset,
|
||||||
|
streamCharset -> {
|
||||||
|
return new Label(streamCharset.getCharset().displayName()
|
||||||
|
+ (streamCharset.hasByteOrderMark() ? " (BOM)" : ""));
|
||||||
|
},
|
||||||
|
new Label(AppI18n.get("app.none")),
|
||||||
|
null);
|
||||||
|
builder.setAccessibleNames(streamCharset -> streamCharset.getNames().get(0));
|
||||||
|
builder.addFilter((charset, filter) -> {
|
||||||
|
return charset.getCharset().displayName().contains(filter);
|
||||||
|
});
|
||||||
|
builder.addHeader(AppI18n.get("app.common"));
|
||||||
|
for (var e : StreamCharset.COMMON) {
|
||||||
|
builder.add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addHeader(AppI18n.get("app.other"));
|
||||||
|
for (var e : StreamCharset.RARE) {
|
||||||
|
builder.add(e);
|
||||||
|
}
|
||||||
|
var comboBox = builder.build();
|
||||||
|
comboBox.setVisibleRowCount(16);
|
||||||
|
return comboBox;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.app.util.DataStoreCategoryChoiceComp;
|
import io.xpipe.app.util.DataStoreCategoryChoiceComp;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.core.store.ShellStore;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
@ -105,7 +106,18 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
||||||
selectedCategory).styleClass(Styles.LEFT_PILL);
|
selectedCategory).styleClass(Styles.LEFT_PILL);
|
||||||
var filter = new FilterComp(filterText)
|
var filter = new FilterComp(filterText)
|
||||||
.styleClass(Styles.CENTER_PILL)
|
.styleClass(Styles.CENTER_PILL)
|
||||||
.hgrow();
|
.hgrow()
|
||||||
|
.apply(struc -> {
|
||||||
|
popover.setOnShowing(event -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
struc.getText().requestFocus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var addButton = Comp.of(() -> {
|
var addButton = Comp.of(() -> {
|
||||||
MenuButton m = new MenuButton(null, new FontIcon("mdi2p-plus-box-outline"));
|
MenuButton m = new MenuButton(null, new FontIcon("mdi2p-plus-box-outline"));
|
||||||
|
@ -120,16 +132,7 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
||||||
var top = new HorizontalComp(List.of(category, filter.hgrow(), addButton))
|
var top = new HorizontalComp(List.of(category, filter.hgrow(), addButton))
|
||||||
.styleClass("top")
|
.styleClass("top")
|
||||||
.apply(struc -> struc.get().setFillHeight(true))
|
.apply(struc -> struc.get().setFillHeight(true))
|
||||||
.apply(struc -> {
|
.createRegion();
|
||||||
// Ugly solution to focus the text field
|
|
||||||
// Somehow this does not work through the normal on shown listeners
|
|
||||||
struc.get().getChildren().get(0).focusedProperty().addListener((observable, oldValue, newValue) -> {
|
|
||||||
if (newValue) {
|
|
||||||
((StackPane) struc.get().getChildren().get(1)).getChildren().get(1).requestFocus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.createStructure().get();
|
|
||||||
var r = section.vgrow().createRegion();
|
var r = section.vgrow().createRegion();
|
||||||
var content = new VBox(top, r);
|
var content = new VBox(top, r);
|
||||||
content.setFillWidth(true);
|
content.setFillWidth(true);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.core.store.FileSystemStore;
|
import io.xpipe.core.store.FileSystemStore;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
@ -17,12 +18,14 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ContextualFileReferenceChoiceComp extends SimpleComp {
|
public class FileReferenceChoiceComp extends SimpleComp {
|
||||||
|
|
||||||
|
private final boolean hideFileSystem;
|
||||||
private final Property<DataStoreEntryRef<? extends FileSystemStore>> fileSystem;
|
private final Property<DataStoreEntryRef<? extends FileSystemStore>> fileSystem;
|
||||||
private final Property<String> filePath;
|
private final Property<String> filePath;
|
||||||
|
|
||||||
public <T extends FileSystemStore> ContextualFileReferenceChoiceComp(ObservableValue<DataStoreEntryRef<T>> fileSystem, Property<String> filePath) {
|
public <T extends FileSystemStore> FileReferenceChoiceComp(ObservableValue<DataStoreEntryRef<T>> fileSystem, Property<String> filePath) {
|
||||||
|
this.hideFileSystem = true;
|
||||||
this.fileSystem = new SimpleObjectProperty<>();
|
this.fileSystem = new SimpleObjectProperty<>();
|
||||||
SimpleChangeListener.apply(fileSystem, val -> {
|
SimpleChangeListener.apply(fileSystem, val -> {
|
||||||
this.fileSystem.setValue(val);
|
this.fileSystem.setValue(val);
|
||||||
|
@ -30,15 +33,27 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp {
|
||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FileReferenceChoiceComp(boolean hideFileSystem, Property<DataStoreEntryRef<? extends FileSystemStore>> fileSystem, Property<String> filePath) {
|
||||||
|
this.hideFileSystem = hideFileSystem;
|
||||||
|
this.fileSystem = fileSystem != null ? fileSystem : new SimpleObjectProperty<>();
|
||||||
|
this.filePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Region createSimple() {
|
protected Region createSimple() {
|
||||||
|
var fileSystemChoiceComp =
|
||||||
|
new FileSystemStoreChoiceComp(fileSystem).grow(false, true).styleClass(Styles.LEFT_PILL);
|
||||||
|
if (hideFileSystem) {
|
||||||
|
fileSystemChoiceComp.hide(new SimpleBooleanProperty(true));
|
||||||
|
}
|
||||||
|
|
||||||
var fileNameComp = new TextFieldComp(filePath)
|
var fileNameComp = new TextFieldComp(filePath)
|
||||||
.apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS))
|
.apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS))
|
||||||
.styleClass(Styles.LEFT_PILL)
|
.styleClass(hideFileSystem ? Styles.LEFT_PILL : Styles.CENTER_PILL)
|
||||||
.grow(false, true);
|
.grow(false, true);
|
||||||
|
|
||||||
var fileBrowseButton = new ButtonComp(null, new FontIcon("mdi2f-folder-open-outline"), () -> {
|
var fileBrowseButton = new ButtonComp(null, new FontIcon("mdi2f-folder-open-outline"), () -> {
|
||||||
StandaloneFileBrowser.openSingleFile(() -> fileSystem.getValue(), fileStore -> {
|
StandaloneFileBrowser.openSingleFile(() -> hideFileSystem ? fileSystem.getValue() : null, fileStore -> {
|
||||||
if (fileStore == null) {
|
if (fileStore == null) {
|
||||||
filePath.setValue(null);
|
filePath.setValue(null);
|
||||||
fileSystem.setValue(null);
|
fileSystem.setValue(null);
|
||||||
|
@ -51,7 +66,7 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp {
|
||||||
.styleClass(Styles.RIGHT_PILL)
|
.styleClass(Styles.RIGHT_PILL)
|
||||||
.grow(false, true);
|
.grow(false, true);
|
||||||
|
|
||||||
var layout = new HorizontalComp(List.of(fileNameComp, fileBrowseButton))
|
var layout = new HorizontalComp(List.of(fileSystemChoiceComp, fileNameComp, fileBrowseButton))
|
||||||
.apply(struc -> struc.get().setFillHeight(true));
|
.apply(struc -> struc.get().setFillHeight(true));
|
||||||
|
|
||||||
layout.apply(struc -> {
|
layout.apply(struc -> {
|
|
@ -0,0 +1,53 @@
|
||||||
|
package io.xpipe.app.fxcomps.impl;
|
||||||
|
|
||||||
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
|
import io.xpipe.app.storage.DataStorage;
|
||||||
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
|
import io.xpipe.app.util.CustomComboBoxBuilder;
|
||||||
|
import io.xpipe.core.store.FileSystemStore;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
public class FileSystemStoreChoiceComp extends SimpleComp {
|
||||||
|
|
||||||
|
private final Property<DataStoreEntryRef<? extends FileSystemStore>> selected;
|
||||||
|
|
||||||
|
public FileSystemStoreChoiceComp(Property<DataStoreEntryRef<? extends FileSystemStore>> selected) {
|
||||||
|
this.selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getName(DataStoreEntryRef<? extends FileSystemStore> store) {
|
||||||
|
return store.get().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Region createGraphic(DataStoreEntryRef<? extends FileSystemStore> s) {
|
||||||
|
var provider = s.get().getProvider();
|
||||||
|
var img = PrettyImageHelper.ofFixedSquare(provider.getDisplayIconFileName(s.getStore()), 16);
|
||||||
|
return new Label(getName(s), img.createRegion());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Region createDisplayGraphic(DataStoreEntryRef<? extends FileSystemStore> s) {
|
||||||
|
var provider = s.get().getProvider();
|
||||||
|
var img = PrettyImageHelper.ofFixedSquare(provider.getDisplayIconFileName(s.getStore()), 16);
|
||||||
|
return new Label(null, img.createRegion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var comboBox = new CustomComboBoxBuilder<>(selected, this::createGraphic, null, v -> true);
|
||||||
|
comboBox.setAccessibleNames(FileSystemStoreChoiceComp::getName);
|
||||||
|
comboBox.setSelectedDisplay(this::createDisplayGraphic);
|
||||||
|
DataStorage.get().getUsableEntries().stream()
|
||||||
|
.filter(e -> e.getStore() instanceof FileSystemStore)
|
||||||
|
.map(DataStoreEntry::<FileSystemStore>ref)
|
||||||
|
.forEach(comboBox::add);
|
||||||
|
ComboBox<Node> cb = comboBox.build();
|
||||||
|
cb.getStyleClass().add("choice-comp");
|
||||||
|
cb.setMaxWidth(45);
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import io.xpipe.app.core.AppImages;
|
||||||
import io.xpipe.app.fxcomps.SimpleComp;
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||||
import io.xpipe.app.issue.TrackEvent;
|
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.core.store.FileNames;
|
import io.xpipe.core.store.FileNames;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
@ -79,7 +78,6 @@ public class PrettyImageComp extends SimpleComp {
|
||||||
} else if (AppImages.hasNormalImage(image.getValue().replace("-dark", ""))) {
|
} else if (AppImages.hasNormalImage(image.getValue().replace("-dark", ""))) {
|
||||||
return AppImages.image(image.getValue().replace("-dark", ""));
|
return AppImages.image(image.getValue().replace("-dark", ""));
|
||||||
} else {
|
} else {
|
||||||
TrackEvent.withWarn("Image file not found").tag("file",image.getValue()).handle();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,49 +6,37 @@ import io.xpipe.core.store.FileNames;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class PrettyImageHelper {
|
public class PrettyImageHelper {
|
||||||
|
|
||||||
public static Optional<Comp<?>> rasterizedIfExists(String img, int width, int height) {
|
public static Comp<?> ofFixedSquare(String img, int size) {
|
||||||
if (img != null && img.endsWith(".svg")) {
|
if (img != null && img.endsWith(".svg")) {
|
||||||
var base = FileNames.getBaseName(img);
|
var base = FileNames.getBaseName(img);
|
||||||
var renderedName = base + "-" + height + ".png";
|
var renderedName = base + "-" + size + ".png";
|
||||||
if (AppImages.hasNormalImage(base + "-" + height + ".png")) {
|
if (AppImages.hasNormalImage(base + "-" + size + ".png")) {
|
||||||
return Optional.of(new PrettyImageComp(new SimpleStringProperty(renderedName), width, height));
|
return new PrettyImageComp(new SimpleStringProperty(renderedName), size, size);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Comp<?> ofFixedSquare(String img, int size) {
|
|
||||||
return ofFixedSize(img, size, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Comp<?> ofFixedSize(String img, int w, int h) {
|
|
||||||
if (img == null) {
|
|
||||||
return new PrettyImageComp(new SimpleStringProperty(null), w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rasterized = rasterizedIfExists(img, w, h);
|
|
||||||
if (rasterized.isPresent()) {
|
|
||||||
return rasterized.get();
|
|
||||||
} else {
|
} else {
|
||||||
|
return new PrettySvgComp(new SimpleStringProperty(img), size, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PrettyImageComp(new SimpleStringProperty(img), size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Comp<?> ofFixed(String img, int w, int h) {
|
||||||
|
if (w == h) {
|
||||||
|
return ofFixedSquare(img, w);
|
||||||
|
}
|
||||||
|
|
||||||
return img.endsWith(".svg") ? new PrettySvgComp(new SimpleStringProperty(img), w, h) : new PrettyImageComp(new SimpleStringProperty(img), w, h);
|
return img.endsWith(".svg") ? new PrettySvgComp(new SimpleStringProperty(img), w, h) : new PrettyImageComp(new SimpleStringProperty(img), w, h);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static Comp<?> ofSvg(ObservableValue<String> img, int w, int h) {
|
public static Comp<?> ofSvg(ObservableValue<String> img, int w, int h) {
|
||||||
return new PrettySvgComp(img, w, h);
|
return new PrettySvgComp(img, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Comp<?> ofRasterized(ObservableValue<String> img, int w, int h) {
|
|
||||||
return new PrettyImageComp(img, w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Comp<?> ofFixedSmallSquare(String img) {
|
public static Comp<?> ofFixedSmallSquare(String img) {
|
||||||
return ofFixedSize(img, 16, 16);
|
return ofFixed(img, 16, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package io.xpipe.app.fxcomps.impl;
|
package io.xpipe.app.fxcomps.impl;
|
||||||
|
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.CompStructure;
|
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
@ -9,24 +8,11 @@ import javafx.beans.property.Property;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import lombok.Builder;
|
import javafx.scene.layout.Region;
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class TextAreaComp extends Comp<TextAreaComp.Structure> {
|
public class TextAreaComp extends SimpleComp {
|
||||||
|
|
||||||
@Value
|
|
||||||
@Builder
|
|
||||||
public static class Structure implements CompStructure<AnchorPane> {
|
|
||||||
AnchorPane pane;
|
|
||||||
TextArea textArea;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnchorPane get() {
|
|
||||||
return pane;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Property<String> currentValue;
|
private final Property<String> currentValue;
|
||||||
private final Property<String> lastAppliedValue;
|
private final Property<String> lastAppliedValue;
|
||||||
|
@ -46,7 +32,7 @@ public class TextAreaComp extends Comp<TextAreaComp.Structure> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Structure createBase() {
|
protected Region createSimple() {
|
||||||
var text = new TextArea(currentValue.getValue() != null ? currentValue.getValue() : null);
|
var text = new TextArea(currentValue.getValue() != null ? currentValue.getValue() : null);
|
||||||
text.setPrefRowCount(5);
|
text.setPrefRowCount(5);
|
||||||
text.textProperty().addListener((c, o, n) -> {
|
text.textProperty().addListener((c, o, n) -> {
|
||||||
|
@ -71,12 +57,6 @@ public class TextAreaComp extends Comp<TextAreaComp.Structure> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var anchorPane = new AnchorPane(text);
|
|
||||||
AnchorPane.setBottomAnchor(text, 0.0);
|
|
||||||
AnchorPane.setTopAnchor(text, 0.0);
|
|
||||||
AnchorPane.setLeftAnchor(text, 0.0);
|
|
||||||
AnchorPane.setRightAnchor(text, 0.0);
|
|
||||||
|
|
||||||
if (lazy) {
|
if (lazy) {
|
||||||
var isEqual = Bindings.createBooleanBinding(
|
var isEqual = Bindings.createBooleanBinding(
|
||||||
() -> Objects.equals(lastAppliedValue.getValue(), currentValue.getValue()),
|
() -> Objects.equals(lastAppliedValue.getValue(), currentValue.getValue()),
|
||||||
|
@ -85,14 +65,16 @@ public class TextAreaComp extends Comp<TextAreaComp.Structure> {
|
||||||
var button = new IconButtonComp("mdi2c-checkbox-marked-outline")
|
var button = new IconButtonComp("mdi2c-checkbox-marked-outline")
|
||||||
.hide(isEqual)
|
.hide(isEqual)
|
||||||
.createRegion();
|
.createRegion();
|
||||||
anchorPane.getChildren().add(button);
|
var anchorPane = new AnchorPane(text, button);
|
||||||
AnchorPane.setBottomAnchor(button, 10.0);
|
AnchorPane.setBottomAnchor(button, 10.0);
|
||||||
AnchorPane.setRightAnchor(button, 10.0);
|
AnchorPane.setRightAnchor(button, 10.0);
|
||||||
|
|
||||||
text.prefWidthProperty().bind(anchorPane.widthProperty());
|
text.prefWidthProperty().bind(anchorPane.widthProperty());
|
||||||
text.prefHeightProperty().bind(anchorPane.heightProperty());
|
text.prefHeightProperty().bind(anchorPane.heightProperty());
|
||||||
|
|
||||||
|
return anchorPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Structure(anchorPane, text);
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,11 +304,9 @@ public class BindingsHelper {
|
||||||
if (target.size() - 1 == newList.size() && targetSet.containsAll(newSet)) {
|
if (target.size() - 1 == newList.size() && targetSet.containsAll(newSet)) {
|
||||||
var l = new HashSet<>(targetSet);
|
var l = new HashSet<>(targetSet);
|
||||||
l.removeAll(newSet);
|
l.removeAll(newSet);
|
||||||
if (l.size() > 0) {
|
|
||||||
target.remove(l.iterator().next());
|
target.remove(l.iterator().next());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Other cases are more difficult
|
// Other cases are more difficult
|
||||||
target.setAll(newList);
|
target.setAll(newList);
|
||||||
|
|
|
@ -180,7 +180,7 @@ public class SentryErrorHandler implements ErrorHandler {
|
||||||
s.setTag("terminal", Boolean.toString(ee.isTerminal()));
|
s.setTag("terminal", Boolean.toString(ee.isTerminal()));
|
||||||
s.setTag("omitted", Boolean.toString(ee.isOmitted()));
|
s.setTag("omitted", Boolean.toString(ee.isOmitted()));
|
||||||
s.setTag("diagnostics", Boolean.toString(ee.isShouldSendDiagnostics()));
|
s.setTag("diagnostics", Boolean.toString(ee.isShouldSendDiagnostics()));
|
||||||
s.setTag("logs", Boolean.toString(ee.isShouldSendDiagnostics() && !ee.getAttachments().isEmpty()));
|
s.setTag("logs", Boolean.toString(!ee.getAttachments().isEmpty()));
|
||||||
|
|
||||||
var exMessage = ee.getThrowable() != null ? ee.getThrowable().getMessage() : null;
|
var exMessage = ee.getThrowable() != null ? ee.getThrowable().getMessage() : null;
|
||||||
if (ee.getDescription() != null && !ee.getDescription().equals(exMessage) && ee.isShouldSendDiagnostics()) {
|
if (ee.getDescription() != null && !ee.getDescription().equals(exMessage) && ee.isShouldSendDiagnostics()) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import lombok.NonNull;
|
||||||
|
|
||||||
import java.nio.file.InvalidPathException;
|
import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
@ -37,24 +36,6 @@ public class ContextualFileReference {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<ContextualFileReference> parseIfInDataDirectory(String s) {
|
|
||||||
var cf = of(s);
|
|
||||||
if (cf.serialize().contains("<DATA>")) {
|
|
||||||
return Optional.of(cf);
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<String> resolveIfInDataDirectory(ShellControl shellControl, String s) {
|
|
||||||
if (s.contains("<DATA>")) {
|
|
||||||
var cf = of(s);
|
|
||||||
return Optional.of(cf.toFilePath(shellControl));
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ContextualFileReference of(String s) {
|
public static ContextualFileReference of(String s) {
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
266
app/src/main/java/io/xpipe/app/util/CustomComboBoxBuilder.java
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
package io.xpipe.app.util;
|
||||||
|
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.app.fxcomps.impl.FilterComp;
|
||||||
|
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.geometry.Orientation;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
|
import javafx.scene.control.Separator;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class CustomComboBoxBuilder<T> {
|
||||||
|
|
||||||
|
private final Property<T> selected;
|
||||||
|
private final Function<T, Node> nodeFunction;
|
||||||
|
private ObservableValue<String> emptyAccessibilityName = AppI18n.observable("none");
|
||||||
|
private Function<T, String> accessibleNameFunction;
|
||||||
|
private Function<T, Node> selectedDisplayNodeFunction;
|
||||||
|
private final Map<Node, T> nodeMap = new HashMap<>();
|
||||||
|
private final Map<Node, Runnable> actionsMap = new HashMap<>();
|
||||||
|
private final List<Node> nodes = new ArrayList<>();
|
||||||
|
private final Set<Node> disabledNodes = new HashSet<>();
|
||||||
|
private final Node emptyNode;
|
||||||
|
private final Predicate<T> veto;
|
||||||
|
private final Property<String> filterString = new SimpleStringProperty();
|
||||||
|
private final List<T> filterable = new ArrayList<>();
|
||||||
|
private BiPredicate<T, String> filterPredicate;
|
||||||
|
private Node filterNode;
|
||||||
|
private Function<T, Node> unknownNode;
|
||||||
|
|
||||||
|
public CustomComboBoxBuilder(
|
||||||
|
Property<T> selected, Function<T, Node> nodeFunction, Node emptyNode, Predicate<T> veto) {
|
||||||
|
this.selected = selected;
|
||||||
|
this.nodeFunction = nodeFunction;
|
||||||
|
this.selectedDisplayNodeFunction = nodeFunction;
|
||||||
|
this.emptyNode = emptyNode;
|
||||||
|
this.veto = veto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedDisplay(Function<T, Node> nodeFunction) {
|
||||||
|
selectedDisplayNodeFunction = nodeFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessibleNames(Function<T, String> function) {
|
||||||
|
accessibleNameFunction = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmptyAccessibilityName(ObservableValue<String> n) {
|
||||||
|
emptyAccessibilityName = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAction(Node node, Runnable run) {
|
||||||
|
nodes.add(node);
|
||||||
|
actionsMap.put(node, run);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable(Node node) {
|
||||||
|
disabledNodes.add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnknownNode(Function<T, Node> node) {
|
||||||
|
unknownNode = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node add(T val) {
|
||||||
|
var node = nodeFunction.apply(val);
|
||||||
|
nodeMap.put(node, val);
|
||||||
|
nodes.add(node);
|
||||||
|
if (filterPredicate != null) {
|
||||||
|
filterable.add(val);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSeparator() {
|
||||||
|
var sep = new Separator(Orientation.HORIZONTAL);
|
||||||
|
nodes.add(sep);
|
||||||
|
disabledNodes.add(sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addHeader(String name) {
|
||||||
|
var spacer = new Region();
|
||||||
|
spacer.setPrefHeight(10);
|
||||||
|
var header = new Label(name);
|
||||||
|
header.setAlignment(Pos.CENTER);
|
||||||
|
var v = new VBox(spacer, header, new Separator(Orientation.HORIZONTAL));
|
||||||
|
v.setAccessibleText(name);
|
||||||
|
v.setAlignment(Pos.CENTER);
|
||||||
|
nodes.add(v);
|
||||||
|
disabledNodes.add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFilter(BiPredicate<T, String> filterPredicate) {
|
||||||
|
this.filterPredicate = filterPredicate;
|
||||||
|
|
||||||
|
var spacer = new Region();
|
||||||
|
spacer.setPrefHeight(10);
|
||||||
|
var header = new FilterComp(filterString).createStructure();
|
||||||
|
var v = new VBox(header.get());
|
||||||
|
v.setAlignment(Pos.CENTER);
|
||||||
|
nodes.add(v);
|
||||||
|
filterNode = header.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComboBox<Node> build() {
|
||||||
|
var cb = new ComboBox<Node>();
|
||||||
|
cb.getItems().addAll(nodes);
|
||||||
|
|
||||||
|
cb.setCellFactory((lv) -> {
|
||||||
|
return new Cell();
|
||||||
|
});
|
||||||
|
cb.setButtonCell(new SelectedCell());
|
||||||
|
SimpleChangeListener.apply(selected, c -> {
|
||||||
|
var item = nodeMap.entrySet().stream()
|
||||||
|
.filter(e -> Objects.equals(c, e.getValue()))
|
||||||
|
.map(e -> e.getKey())
|
||||||
|
.findAny()
|
||||||
|
.orElse(c == null || unknownNode == null ? emptyNode : unknownNode.apply(c));
|
||||||
|
cb.setValue(item);
|
||||||
|
});
|
||||||
|
cb.valueProperty().addListener((c, o, n) -> {
|
||||||
|
if (nodeMap.containsKey(n)) {
|
||||||
|
if (veto != null && !veto.test(nodeMap.get(n))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selected.setValue(nodeMap.get(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionsMap.containsKey(n)) {
|
||||||
|
cb.setValue(o);
|
||||||
|
actionsMap.get(n).run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filterPredicate != null) {
|
||||||
|
SimpleChangeListener.apply(filterString, c -> {
|
||||||
|
var filteredNodes = nodes.stream()
|
||||||
|
.filter(e -> e.equals(cb.getValue())
|
||||||
|
|| !(nodeMap.get(e) != null
|
||||||
|
&& (filterable.contains(nodeMap.get(e))
|
||||||
|
&& filterString.getValue() != null
|
||||||
|
&& !filterPredicate.test(nodeMap.get(e), c))))
|
||||||
|
.toList();
|
||||||
|
cb.setItems(FXCollections.observableList(filteredNodes));
|
||||||
|
});
|
||||||
|
|
||||||
|
filterNode.sceneProperty().addListener((c, o, n) -> {
|
||||||
|
if (n != null) {
|
||||||
|
n.getWindow().focusedProperty().addListener((c2, o2, n2) -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
filterNode.requestFocus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
filterNode.requestFocus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emptyNode != null) {
|
||||||
|
emptyNode.setAccessibleText(emptyAccessibilityName.getValue());
|
||||||
|
}
|
||||||
|
if (accessibleNameFunction != null) {
|
||||||
|
nodes.forEach(node -> node.setAccessibleText(accessibleNameFunction.apply(nodeMap.get(node))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SelectedCell extends ListCell<Node> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Node item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
accessibleTextProperty().unbind();
|
||||||
|
if (empty || item.equals(emptyNode)) {
|
||||||
|
if (emptyAccessibilityName != null) {
|
||||||
|
accessibleTextProperty().bind(emptyAccessibilityName);
|
||||||
|
} else {
|
||||||
|
setAccessibleText(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.equals(emptyNode)) {
|
||||||
|
setGraphic(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case for dynamically created unknown nodes
|
||||||
|
if (!nodeMap.containsKey(item)) {
|
||||||
|
setGraphic(item);
|
||||||
|
// Don't expect the accessible name function to properly map this item
|
||||||
|
setAccessibleText(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = nodeMap.get(item);
|
||||||
|
var newNode = selectedDisplayNodeFunction.apply(val);
|
||||||
|
setGraphic(newNode);
|
||||||
|
setAccessibleText(newNode.getAccessibleText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Cell extends ListCell<Node> {
|
||||||
|
|
||||||
|
public Cell() {
|
||||||
|
addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
|
||||||
|
if (!nodeMap.containsKey(getItem())) {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||||
|
if (event.getCode() == KeyCode.ENTER && !nodeMap.containsKey(getItem())) {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Node item, boolean empty) {
|
||||||
|
setGraphic(item);
|
||||||
|
if (getItem() == item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setGraphic(item);
|
||||||
|
if (disabledNodes.contains(item)) {
|
||||||
|
this.setDisable(true);
|
||||||
|
this.setFocusTraversable(false);
|
||||||
|
// this.setPadding(Insets.EMPTY);
|
||||||
|
} else {
|
||||||
|
this.setDisable(false);
|
||||||
|
this.setFocusTraversable(true);
|
||||||
|
setAccessibleText(item.getAccessibleText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 872 B |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 708 B |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 750 B |
Before Width: | Height: | Size: 780 B After Width: | Height: | Size: 780 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1,014 B |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 623 B |
Before Width: | Height: | Size: 575 B |
Before Width: | Height: | Size: 915 B |
Before Width: | Height: | Size: 958 B |
Before Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 911 B After Width: | Height: | Size: 911 B |
Before Width: | Height: | Size: 749 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 730 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 941 B |
Before Width: | Height: | Size: 466 B |
Before Width: | Height: | Size: 434 B |
Before Width: | Height: | Size: 238 B |
Before Width: | Height: | Size: 210 B After Width: | Height: | Size: 210 B |
Before Width: | Height: | Size: 801 B |
Before Width: | Height: | Size: 985 B After Width: | Height: | Size: 985 B |
Before Width: | Height: | Size: 715 B |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 817 B After Width: | Height: | Size: 817 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 686 B |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 594 B |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 696 B |
Before Width: | Height: | Size: 683 B |
Before Width: | Height: | Size: 360 B After Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1,023 B |
Before Width: | Height: | Size: 963 B After Width: | Height: | Size: 963 B |
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 662 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
|
@ -242,10 +242,6 @@
|
||||||
-fx-background-color: -color-success-subtle;
|
-fx-background-color: -color-success-subtle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root.nord .browser .table-row-cell:selected, .root.nord .browser .table-row-cell:hover:selected {
|
|
||||||
-fx-background-color: -color-success-7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.browser .table-row-cell:folder:drag-over {
|
.browser .table-row-cell:folder:drag-over {
|
||||||
-fx-background-color: -color-success-muted;
|
-fx-background-color: -color-success-muted;
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,14 +141,14 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
|
||||||
try (CommandControl c = pc.command("lsb_release -a").start()) {
|
try (CommandControl c = pc.command("lsb_release -a").start()) {
|
||||||
var text = c.readStdoutDiscardErr();
|
var text = c.readStdoutDiscardErr();
|
||||||
if (c.getExitCode() == 0) {
|
if (c.getExitCode() == 0) {
|
||||||
return PropertiesFormatsParser.parse(text, ":").getOrDefault("Description", "Unknown");
|
return PropertiesFormatsParser.parse(text, ":").getOrDefault("Description", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try (CommandControl c = pc.command("cat /etc/*release").start()) {
|
try (CommandControl c = pc.command("cat /etc/*release").start()) {
|
||||||
var text = c.readStdoutDiscardErr();
|
var text = c.readStdoutDiscardErr();
|
||||||
if (c.getExitCode() == 0) {
|
if (c.getExitCode() == 0) {
|
||||||
return PropertiesFormatsParser.parse(text, "=").getOrDefault("PRETTY_NAME", "Unknown");
|
return PropertiesFormatsParser.parse(text, "=").getOrDefault("PRETTY_NAME", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ public interface ProcessControl extends AutoCloseable {
|
||||||
|
|
||||||
ProcessControl withExceptionConverter(ExceptionConverter converter);
|
ProcessControl withExceptionConverter(ExceptionConverter converter);
|
||||||
|
|
||||||
void resetData(boolean cache);
|
void resetData();
|
||||||
|
|
||||||
String prepareTerminalOpen(TerminalInitScriptConfig config) throws Exception;
|
String prepareTerminalOpen(TerminalInitScriptConfig config) throws Exception;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ public interface ProcessControl extends AutoCloseable {
|
||||||
@Override
|
@Override
|
||||||
void close() throws Exception;
|
void close() throws Exception;
|
||||||
|
|
||||||
void kill();
|
void kill() throws Exception;
|
||||||
|
|
||||||
ProcessControl start() throws Exception;
|
ProcessControl start() throws Exception;
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ import java.util.function.Function;
|
||||||
|
|
||||||
public interface ShellControl extends ProcessControl {
|
public interface ShellControl extends ProcessControl {
|
||||||
|
|
||||||
List<UUID> getExitUuids();
|
|
||||||
|
|
||||||
Optional<ShellStore> getSourceStore();
|
Optional<ShellStore> getSourceStore();
|
||||||
|
|
||||||
ShellControl withSourceStore(ShellStore store);
|
ShellControl withSourceStore(ShellStore store);
|
||||||
|
|
|
@ -22,9 +22,8 @@ public class ShellDialects {
|
||||||
public static ShellDialect ZSH;
|
public static ShellDialect ZSH;
|
||||||
public static ShellDialect CSH;
|
public static ShellDialect CSH;
|
||||||
public static ShellDialect FISH;
|
public static ShellDialect FISH;
|
||||||
|
public static ShellDialect UNSUPPORTED;
|
||||||
public static ShellDialect CISCO;
|
public static ShellDialect CISCO;
|
||||||
public static ShellDialect RBASH;
|
|
||||||
|
|
||||||
public static List<ShellDialect> getStartableDialects() {
|
public static List<ShellDialect> getStartableDialects() {
|
||||||
return ALL.stream().filter(dialect -> dialect.getOpenCommand() != null).filter(dialect -> dialect != SH_BSD).toList();
|
return ALL.stream().filter(dialect -> dialect.getOpenCommand() != null).filter(dialect -> dialect != SH_BSD).toList();
|
||||||
|
@ -51,8 +50,8 @@ public class ShellDialects {
|
||||||
ASH = byId("ash");
|
ASH = byId("ash");
|
||||||
SH = byId("sh");
|
SH = byId("sh");
|
||||||
SH_BSD = byId("shBsd");
|
SH_BSD = byId("shBsd");
|
||||||
|
UNSUPPORTED = byId("unsupported");
|
||||||
CISCO = byId("cisco");
|
CISCO = byId("cisco");
|
||||||
RBASH = byId("rbash");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
3
dist/changelogs/1.7.14.md
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
This is just a small hotfix update to fix a few breaking issues:
|
||||||
|
- Fix performance regression in JavaFX by downgrading version temporarily
|
||||||
|
- Fix .deb installers not being able to resolve some packages on Ubuntu < 22
|
|
@ -59,7 +59,7 @@ open module io.xpipe.ext.base {
|
||||||
DeleteStoreChildrenAction,
|
DeleteStoreChildrenAction,
|
||||||
BrowseStoreAction;
|
BrowseStoreAction;
|
||||||
provides DataStoreProvider with
|
provides DataStoreProvider with
|
||||||
SimpleScriptStoreProvider,
|
|
||||||
ScriptGroupStoreProvider,
|
ScriptGroupStoreProvider,
|
||||||
|
SimpleScriptStoreProvider,
|
||||||
InMemoryStoreProvider;
|
InMemoryStoreProvider;
|
||||||
}
|
}
|
||||||
|
|
After Width: | Height: | Size: 4 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 4.6 KiB |
2
version
|
@ -1 +1 @@
|
||||||
1.7.13
|
1.7.14
|