Improve settings menu and connection creation [release]

This commit is contained in:
crschnick 2023-02-13 23:04:20 +00:00
parent 28a8c95c71
commit 287f3d084d
25 changed files with 304 additions and 74 deletions

View file

@ -46,7 +46,7 @@ dependencies {
implementation group: 'org.kordamp.ikonli', name: 'ikonli-materialdesign2-pack', version: "12.2.0" implementation group: 'org.kordamp.ikonli', name: 'ikonli-materialdesign2-pack', version: "12.2.0"
implementation group: 'org.kordamp.ikonli', name: 'ikonli-javafx', version: "12.2.0" implementation group: 'org.kordamp.ikonli', name: 'ikonli-javafx', version: "12.2.0"
implementation group: 'org.kordamp.ikonli', name: 'ikonli-material-pack', version: "12.2.0" implementation group: 'org.kordamp.ikonli', name: 'ikonli-material-pack', version: "12.2.0"
implementation group: 'com.dlsc.preferencesfx', name: 'preferencesfx-core', version: '11.15.0' implementation name: 'preferencesfx-core-11.15.0'
implementation group: 'com.dlsc.formsfx', name: 'formsfx-core', version: '11.6.0' implementation group: 'com.dlsc.formsfx', name: 'formsfx-core', version: '11.6.0'
implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.0' implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.0'
implementation 'io.xpipe:modulefs:0.1.4' implementation 'io.xpipe:modulefs:0.1.4'
@ -92,6 +92,7 @@ List<String> jvmRunArgs = [
"--add-opens", "java.base/java.lang=io.xpipe.core", "--add-opens", "java.base/java.lang=io.xpipe.core",
"--add-opens", "com.dustinredmond.fxtrayicon/com.dustinredmond.fxtrayicon=io.xpipe.app", "--add-opens", "com.dustinredmond.fxtrayicon/com.dustinredmond.fxtrayicon=io.xpipe.app",
"--add-opens", "net.synedra.validatorfx/net.synedra.validatorfx=io.xpipe.extension", "--add-opens", "net.synedra.validatorfx/net.synedra.validatorfx=io.xpipe.extension",
"--add-opens", 'com.dlsc.preferencesfx/com.dlsc.preferencesfx.view=io.xpipe.app',
"-Xmx8g", "-Xmx8g",
"--enable-preview", "--enable-preview",
// "-XX:+ExitOnOutOfMemoryError", // "-XX:+ExitOnOutOfMemoryError",

View file

@ -22,7 +22,7 @@ import lombok.experimental.FieldDefaults;
@AllArgsConstructor @AllArgsConstructor
public class DataStoreSelectorComp extends Comp<CompStructure<Button>> { public class DataStoreSelectorComp extends Comp<CompStructure<Button>> {
DataStoreProvider.Category category; DataStoreProvider.DataCategory category;
Property<DataStore> chosenStore; Property<DataStore> chosenStore;
@Override @Override
@ -30,7 +30,7 @@ public class DataStoreSelectorComp extends Comp<CompStructure<Button>> {
var button = new JFXButton(); var button = new JFXButton();
button.setGraphic(getGraphic()); button.setGraphic(getGraphic());
button.setOnAction(e -> { button.setOnAction(e -> {
GuiDsStoreCreator.show("inProgress", null, null, category, entry -> { GuiDsStoreCreator.show("inProgress", null, null, v -> v.getCategory().equals(category), entry -> {
chosenStore.setValue(entry.getStore()); chosenStore.setValue(entry.getStore());
}); });
e.consume(); e.consume();

View file

@ -32,7 +32,7 @@ public class DsDbStoreChooserComp extends SimpleComp {
var filter = Bindings.createObjectBinding( var filter = Bindings.createObjectBinding(
() -> (Predicate<DataStoreEntry>) e -> { () -> (Predicate<DataStoreEntry>) e -> {
if (provider.getValue() == null) { if (provider.getValue() == null) {
return e.getProvider().getCategory() == DataStoreProvider.Category.DATABASE; return e.getProvider().getCategory() == DataStoreProvider.DataCategory.DATABASE;
} }
return provider.getValue().couldSupportStore(e.getStore()); return provider.getValue().couldSupportStore(e.getStore());
@ -42,7 +42,7 @@ public class DsDbStoreChooserComp extends SimpleComp {
var connections = new TabPaneComp.Entry( var connections = new TabPaneComp.Entry(
I18n.observable("savedConnections"), I18n.observable("savedConnections"),
"mdi2m-monitor", "mdi2m-monitor",
NamedStoreChoiceComp.create(filter, input, DataStoreProvider.Category.DATABASE) NamedStoreChoiceComp.create(filter, input, DataStoreProvider.DataCategory.DATABASE)
.styleClass("store-local-file-chooser")); .styleClass("store-local-file-chooser"));
var pane = new TabPaneComp(new SimpleObjectProperty<>(connections), List.of(connections)); var pane = new TabPaneComp(new SimpleObjectProperty<>(connections), List.of(connections));

View file

@ -18,28 +18,23 @@ import lombok.AllArgsConstructor;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.List; import java.util.List;
import java.util.function.Predicate;
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@AllArgsConstructor @AllArgsConstructor
public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>>> { public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>>> {
DataStoreProvider.Category type; Predicate<DataStoreProvider> filter;
Property<DataStoreProvider> provider; Property<DataStoreProvider> provider;
private Region createDefaultNode() { private Region createDefaultNode() {
return switch (type) { return JfxHelper.createNamedEntry(
case STREAM -> JfxHelper.createNamedEntry( I18n.get("selectType"), I18n.get("selectTypeDescription"), "machine_icon.png");
I18n.get("selectStreamType"), I18n.get("selectStreamTypeDescription"), "file_icon.png");
case SHELL -> JfxHelper.createNamedEntry(
I18n.get("selectShellType"), I18n.get("selectShellTypeDescription"), "machine_icon.png");
case DATABASE -> JfxHelper.createNamedEntry(
I18n.get("selectDatabaseType"), I18n.get("selectDatabaseTypeDescription"), "db_icon.png");
};
} }
private List<DataStoreProvider> getProviders() { private List<DataStoreProvider> getProviders() {
return DataStoreProviders.getAll().stream() return DataStoreProviders.getAll().stream()
.filter(p -> p.getCategory() == type) .filter(filter)
.toList(); .toList();
} }

View file

@ -114,14 +114,14 @@ public class DsStreamStoreChoiceComp extends SimpleComp implements Validatable {
var named = new TabPaneComp.Entry( var named = new TabPaneComp.Entry(
I18n.observable("stored"), I18n.observable("stored"),
"mdrmz-storage", "mdrmz-storage",
NamedStoreChoiceComp.create(filter, namedStore, DataStoreProvider.Category.STREAM)); NamedStoreChoiceComp.create(filter, namedStore, DataStoreProvider.DataCategory.STREAM));
var otherStore = new SimpleObjectProperty<DataStore>( var otherStore = new SimpleObjectProperty<DataStore>(
localStore.get() == null && remoteStore.get() == null && !isNamedStore ? selected.getValue() : null); localStore.get() == null && remoteStore.get() == null && !isNamedStore ? selected.getValue() : null);
var other = new TabPaneComp.Entry( var other = new TabPaneComp.Entry(
I18n.observable("other"), I18n.observable("other"),
"mdrmz-web_asset", "mdrmz-web_asset",
new DataStoreSelectorComp(DataStoreProvider.Category.STREAM, otherStore)); new DataStoreSelectorComp(DataStoreProvider.DataCategory.STREAM, otherStore));
var selectedTab = new SimpleObjectProperty<TabPaneComp.Entry>(); var selectedTab = new SimpleObjectProperty<TabPaneComp.Entry>();
if (localStore.get() != null) { if (localStore.get() != null) {

View file

@ -37,6 +37,7 @@ import lombok.experimental.FieldDefaults;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate;
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> { public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
@ -44,7 +45,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
MultiStepComp parent; MultiStepComp parent;
Property<DataStoreProvider> provider; Property<DataStoreProvider> provider;
Property<DataStore> input; Property<DataStore> input;
DataStoreProvider.Category generalType; Predicate<DataStoreProvider> filter;
BooleanProperty busy = new SimpleBooleanProperty(); BooleanProperty busy = new SimpleBooleanProperty();
Property<Validator> validator = new SimpleObjectProperty<>(new SimpleValidator()); Property<Validator> validator = new SimpleObjectProperty<>(new SimpleValidator());
Property<String> messageProp = new SimpleStringProperty(); Property<String> messageProp = new SimpleStringProperty();
@ -58,13 +59,13 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
MultiStepComp parent, MultiStepComp parent,
Property<DataStoreProvider> provider, Property<DataStoreProvider> provider,
Property<DataStore> input, Property<DataStore> input,
DataStoreProvider.Category generalType, Predicate<DataStoreProvider> filter,
String initialName) { String initialName) {
super(null); super(null);
this.parent = parent; this.parent = parent;
this.provider = provider; this.provider = provider;
this.input = input; this.input = input;
this.generalType = generalType; this.filter = filter;
this.name = new SimpleStringProperty(initialName); this.name = new SimpleStringProperty(initialName);
this.input.addListener((c, o, n) -> { this.input.addListener((c, o, n) -> {
changedSinceError.setValue(true); changedSinceError.setValue(true);
@ -88,7 +89,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
} }
public static void showEdit(DataStoreEntry e) { public static void showEdit(DataStoreEntry e) {
show(e.getName(), e.getProvider(), e.getStore(), e.getProvider().getCategory(), newE -> { show(e.getName(), e.getProvider(), e.getStore(), v -> true, newE -> {
ThreadHelper.runAsync(() -> { ThreadHelper.runAsync(() -> {
e.applyChanges(newE); e.applyChanges(newE);
if (!DataStorage.get().getStores().contains(e)) { if (!DataStorage.get().getStores().contains(e)) {
@ -99,9 +100,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
}); });
} }
public static void showCreation(DataStoreProvider.Category cat) { public static void showCreation(Predicate<DataStoreProvider> filter) {
show(null, null, null, filter, e -> {
show(null, null, null, cat, e -> {
try { try {
DataStorage.get().addStore(e); DataStorage.get().addStore(e);
} catch (Exception ex) { } catch (Exception ex) {
@ -114,13 +114,11 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
String initialName, String initialName,
DataStoreProvider provider, DataStoreProvider provider,
DataStore s, DataStore s,
DataStoreProvider.Category cat, Predicate<DataStoreProvider> filter,
Consumer<DataStoreEntry> con) { Consumer<DataStoreEntry> con) {
var prop = new SimpleObjectProperty<DataStoreProvider>(provider); var prop = new SimpleObjectProperty<DataStoreProvider>(provider);
var store = new SimpleObjectProperty<DataStore>(s); var store = new SimpleObjectProperty<DataStore>(s);
var name = cat == DataStoreProvider.Category.SHELL var name = "addConnection";
? "addShellTitle"
: cat == DataStoreProvider.Category.DATABASE ? "addDatabaseTitle" : "addStreamTitle";
Platform.runLater(() -> { Platform.runLater(() -> {
var stage = AppWindowHelper.sideWindow( var stage = AppWindowHelper.sideWindow(
I18n.get(name), I18n.get(name),
@ -128,7 +126,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
return new MultiStepComp() { return new MultiStepComp() {
private final GuiDsStoreCreator creator = private final GuiDsStoreCreator creator =
new GuiDsStoreCreator(this, prop, store, cat, initialName); new GuiDsStoreCreator(this, prop, store, filter, initialName);
@Override @Override
protected List<Entry> setup() { protected List<Entry> setup() {
@ -182,7 +180,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
@Override @Override
public CompStructure<? extends Region> createBase() { public CompStructure<? extends Region> createBase() {
var layout = new BorderPane(); var layout = new BorderPane();
var providerChoice = new DsStoreProviderChoiceComp(generalType, provider); var providerChoice = new DsStoreProviderChoiceComp(filter, provider);
providerChoice.apply(GrowAugment.create(true, false)); providerChoice.apply(GrowAugment.create(true, false));
SimpleChangeListener.apply(provider, n -> { SimpleChangeListener.apply(provider, n -> {

View file

@ -41,7 +41,7 @@ import java.util.function.Predicate;
public class NamedStoreChoiceComp extends SimpleComp implements Validatable { public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
private final ObservableValue<Predicate<DataStore>> filter; private final ObservableValue<Predicate<DataStore>> filter;
private final DataStoreProvider.Category category; private final DataStoreProvider.DataCategory category;
private final Property<? extends DataStore> selected; private final Property<? extends DataStore> selected;
private final StringProperty filterString = new SimpleStringProperty(); private final StringProperty filterString = new SimpleStringProperty();
@ -53,7 +53,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
public NamedStoreChoiceComp( public NamedStoreChoiceComp(
ObservableValue<Predicate<DataStore>> filter, ObservableValue<Predicate<DataStore>> filter,
Property<? extends DataStore> selected, Property<? extends DataStore> selected,
DataStoreProvider.Category category) { DataStoreProvider.DataCategory category) {
this.filter = filter; this.filter = filter;
this.selected = selected; this.selected = selected;
this.category = category; this.category = category;
@ -63,7 +63,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
public static NamedStoreChoiceComp create( public static NamedStoreChoiceComp create(
ObservableValue<Predicate<DataStoreEntry>> filter, ObservableValue<Predicate<DataStoreEntry>> filter,
Property<? extends DataStore> selected, Property<? extends DataStore> selected,
DataStoreProvider.Category category) { DataStoreProvider.DataCategory category) {
return new NamedStoreChoiceComp( return new NamedStoreChoiceComp(
Bindings.createObjectBinding( Bindings.createObjectBinding(
() -> { () -> {
@ -142,7 +142,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
var text = new LabelComp(I18n.observable("noMatchingStoreFound")) var text = new LabelComp(I18n.observable("noMatchingStoreFound"))
.apply(struc -> VBox.setVgrow(struc.get(), Priority.ALWAYS)); .apply(struc -> VBox.setVgrow(struc.get(), Priority.ALWAYS));
var addButton = new ButtonComp(I18n.observable("addStore"), null, () -> { var addButton = new ButtonComp(I18n.observable("addStore"), null, () -> {
GuiDsStoreCreator.showCreation(category); GuiDsStoreCreator.showCreation(v -> v.getCategory().equals(category));
}); });
var notice = new VerticalComp(List.of(text, addButton)) var notice = new VerticalComp(List.of(text, addButton))
.apply(struc -> { .apply(struc -> {

View file

@ -20,28 +20,35 @@ public class StoreCreationBarComp extends SimpleComp {
@Override @Override
protected Region createSimple() { protected Region createSimple() {
var newOtherStore = new ButtonComp(
I18n.observable("addOther"), new FontIcon("mdi2c-card-plus-outline"), () -> {
GuiDsStoreCreator.showCreation(v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.OTHER));
})
.shortcut(new KeyCodeCombination(KeyCode.C, KeyCombination.SHORTCUT_DOWN))
.apply(new FancyTooltipAugment<>("addOther"));
var newStreamStore = new ButtonComp( var newStreamStore = new ButtonComp(
I18n.observable("addStreamStore"), new FontIcon("mdi2c-card-plus-outline"), () -> { I18n.observable("addCommand"), new FontIcon("mdi2c-code-greater-than"), () -> {
GuiDsStoreCreator.showCreation(DataStoreProvider.Category.STREAM); GuiDsStoreCreator.showCreation(v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.COMMAND));
}) })
.shortcut(new KeyCodeCombination(KeyCode.L, KeyCombination.SHORTCUT_DOWN)) .shortcut(new KeyCodeCombination(KeyCode.C, KeyCombination.SHORTCUT_DOWN))
.apply(new FancyTooltipAugment<>("addStreamStore")); .apply(new FancyTooltipAugment<>("addCommand"));
var newShellStore = new ButtonComp( var newShellStore = new ButtonComp(
I18n.observable("addShellStore"), new FontIcon("mdi2h-home-plus-outline"), () -> { I18n.observable("addHost"), new FontIcon("mdi2h-home-plus-outline"), () -> {
GuiDsStoreCreator.showCreation(DataStoreProvider.Category.SHELL); GuiDsStoreCreator.showCreation(v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.HOST));
}) })
.shortcut(new KeyCodeCombination(KeyCode.M, KeyCombination.SHORTCUT_DOWN)) .shortcut(new KeyCodeCombination(KeyCode.H, KeyCombination.SHORTCUT_DOWN))
.apply(new FancyTooltipAugment<>("addShellStore")); .apply(new FancyTooltipAugment<>("addHost"));
var newDbStore = new ButtonComp( var newDbStore = new ButtonComp(
I18n.observable("addDatabaseStore"), new FontIcon("mdi2d-database-plus-outline"), () -> { I18n.observable("addDatabase"), new FontIcon("mdi2d-database-plus-outline"), () -> {
GuiDsStoreCreator.showCreation(DataStoreProvider.Category.DATABASE); GuiDsStoreCreator.showCreation(v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.DATABASE));
}) })
.shortcut(new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN)) .shortcut(new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN))
.apply(new FancyTooltipAugment<>("addDatabaseStore")); .apply(new FancyTooltipAugment<>("addDatabase"));
var box = new VerticalComp(List.of(newShellStore, newDbStore, newStreamStore)); var box = new VerticalComp(List.of(newShellStore, newDbStore, newStreamStore, newOtherStore));
box.apply(s -> AppFont.medium(s.get())); box.apply(s -> AppFont.medium(s.get()));
var bar = box.createRegion(); var bar = box.createRegion();
bar.getStyleClass().add("bar"); bar.getStyleClass().add("bar");

View file

@ -254,7 +254,7 @@ public class AppExtensionManager {
extendedLayer = extendedLayer =
ModuleLayer.defineModulesWithOneLoader(cf, extended, scl).layer(); ModuleLayer.defineModulesWithOneLoader(cf, extended, scl).layer();
} else { } else {
extendedLayer = ModuleLayer.boot(); extendedLayer = baseLayer;
} }
addNativeLibrariesToPath(); addNativeLibrariesToPath();

View file

@ -135,6 +135,15 @@ public class AppI18n implements I18n {
return key; return key;
} }
public boolean containsKey(String s) {
var key = getKey(s);
if (translations == null) {
return false;
}
return translations.containsKey(key);
}
public String getLocalised(String s, Object... vars) { public String getLocalised(String s, Object... vars) {
var key = getKey(s); var key = getKey(s);

View file

@ -15,7 +15,7 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange
@Override @Override
public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { public Response handleRequest(BeaconHandler handler, Request msg) throws Exception {
var categories = DataStoreProvider.Category.values(); var categories = DataStoreProvider.DataCategory.values();
var all = DataStoreProviders.getAll(); var all = DataStoreProviders.getAll();
var map = Arrays.stream(categories) var map = Arrays.stream(categories)
.collect(Collectors.toMap(category -> getName(category), category -> all.stream() .collect(Collectors.toMap(category -> getName(category), category -> all.stream()
@ -31,7 +31,7 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange
return Response.builder().entries(map).build(); return Response.builder().entries(map).build();
} }
private String getName(DataStoreProvider.Category category) { private String getName(DataStoreProvider.DataCategory category) {
return category.name().substring(0, 1).toUpperCase() return category.name().substring(0, 1).toUpperCase()
+ category.name().substring(1).toLowerCase(); + category.name().substring(1).toLowerCase();
} }

View file

@ -1,5 +1,6 @@
package io.xpipe.app.prefs; package io.xpipe.app.prefs;
import com.dlsc.formsfx.model.structure.Form;
import com.dlsc.formsfx.model.util.TranslationService; import com.dlsc.formsfx.model.util.TranslationService;
import com.dlsc.preferencesfx.PreferencesFxEvent; import com.dlsc.preferencesfx.PreferencesFxEvent;
import com.dlsc.preferencesfx.history.History; import com.dlsc.preferencesfx.history.History;
@ -11,6 +12,8 @@ import com.dlsc.preferencesfx.view.*;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.event.EventType; import javafx.event.EventType;
import javafx.scene.control.ScrollPane;
import lombok.SneakyThrows;
import java.util.List; import java.util.List;
@ -56,10 +59,20 @@ public class AppPreferencesFx {
public void setupControls() { public void setupControls() {
undoRedoBox = new UndoRedoBox(preferencesFxModel.getHistory()); undoRedoBox = new UndoRedoBox(preferencesFxModel.getHistory());
breadCrumbView = new BreadCrumbView(preferencesFxModel, undoRedoBox); breadCrumbView = new BreadCrumbView(preferencesFxModel, undoRedoBox) {
@Override
public void initializeParts() {
}
@Override
public void layoutParts() {
}
};
breadCrumbPresenter = new BreadCrumbPresenter(preferencesFxModel, breadCrumbView); breadCrumbPresenter = new BreadCrumbPresenter(preferencesFxModel, breadCrumbView);
categoryController = new CategoryController(); categoryController = new CategoryController();
categoryController.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
categoryController.setFitToWidth(true);
initializeCategoryViews(); initializeCategoryViews();
// display initial category // display initial category
@ -88,9 +101,24 @@ public class AppPreferencesFx {
*/ */
private void initializeCategoryViews() { private void initializeCategoryViews() {
preferencesFxModel.getFlatCategoriesLst().forEach(category -> { preferencesFxModel.getFlatCategoriesLst().forEach(category -> {
CategoryView categoryView = new CategoryView(preferencesFxModel, category); var categoryView = new CustomCategoryView(preferencesFxModel, category);
CategoryPresenter categoryPresenter = CategoryPresenter categoryPresenter =
new CategoryPresenter(preferencesFxModel, category, categoryView, breadCrumbPresenter); new CategoryPresenter(preferencesFxModel, category, categoryView, breadCrumbPresenter) {
@Override
@SneakyThrows
public void initializeViewParts() {
var formMethod = CategoryPresenter.class.getDeclaredMethod("createForm");
formMethod.setAccessible(true);
var formField = CategoryPresenter.class.getDeclaredField("form");
formField.setAccessible(true);
formField.set(this, formMethod.invoke(this));
categoryView.initializeFormRenderer((Form) formField.get(this));
this.addI18nListener();
this.addInstantPersistenceListener();
}
};
categoryController.addView(category, categoryView, categoryPresenter); categoryController.addView(category, categoryView, categoryPresenter);
}); });
} }

View file

@ -402,17 +402,22 @@ public class AppPrefs {
Category.of( Category.of(
"system", "system",
Group.of( Group.of(
"appBehaviour",
Setting.of( Setting.of(
"externalStartupBehaviour", "externalStartupBehaviour",
externalStartupBehaviourControl, externalStartupBehaviourControl,
externalStartupBehaviour), externalStartupBehaviour),
Setting.of("closeBehaviour", closeBehaviourControl, closeBehaviour), Setting.of("closeBehaviour", closeBehaviourControl, closeBehaviour)),
Group.of(
"updates",
Setting.of("automaticallyUpdate", automaticallyUpdateField, automaticallyUpdate) Setting.of("automaticallyUpdate", automaticallyUpdateField, automaticallyUpdate)
.applyVisibility(VisibilityProperty.of(new SimpleBooleanProperty( .applyVisibility(VisibilityProperty.of(new SimpleBooleanProperty(
XPipeDistributionType.get().supportsUpdate()))), XPipeDistributionType.get().supportsUpdate()))),
Setting.of("updateToPrereleases", updateToPrereleasesField, updateToPrereleases) Setting.of("updateToPrereleases", updateToPrereleasesField, updateToPrereleases)
.applyVisibility(VisibilityProperty.of(new SimpleBooleanProperty( .applyVisibility(VisibilityProperty.of(new SimpleBooleanProperty(
XPipeDistributionType.get().supportsUpdate()))), XPipeDistributionType.get().supportsUpdate())))),
Group.of(
"advanced",
Setting.of("storageDirectory", storageDirectoryControl, internalStorageDirectory), Setting.of("storageDirectory", storageDirectoryControl, internalStorageDirectory),
Setting.of("logLevel", logLevelField, internalLogLevel), Setting.of("logLevel", logLevelField, internalLogLevel),
Setting.of("developerMode", developerModeField, internalDeveloperMode))), Setting.of("developerMode", developerModeField, internalDeveloperMode))),
@ -423,14 +428,13 @@ public class AppPrefs {
Setting.of("language", languageControl, languageInternal), Setting.of("language", languageControl, languageInternal),
Setting.of("theme", themeControl, themeInternal), Setting.of("theme", themeControl, themeInternal),
Setting.of("useSystemFont", useSystemFontInternal), Setting.of("useSystemFont", useSystemFontInternal),
Setting.of("tooltipDelay", tooltipDelayInternal, tooltipDelayMin, tooltipDelayMax), Setting.of("tooltipDelay", tooltipDelayInternal, tooltipDelayMin, tooltipDelayMax)),
Setting.of("fontSize", fontSizeInternal, fontSizeMin, fontSizeMax)),
Group.of("windowOptions", Setting.of("saveWindowLocation", saveWindowLocationInternal))), Group.of("windowOptions", Setting.of("saveWindowLocation", saveWindowLocationInternal))),
Category.of( Category.of(
"integrations", "integrations",
Group.of( Group.of(
"editor", "editor",
Setting.of("defaultProgram", externalEditorControl, externalEditor), Setting.of("editorProgram", externalEditorControl, externalEditor),
Setting.of("customEditorCommand", customEditorCommandControl, customEditorCommand) Setting.of("customEditorCommand", customEditorCommandControl, customEditorCommand)
.applyVisibility(VisibilityProperty.of( .applyVisibility(VisibilityProperty.of(
externalEditor.isEqualTo(ExternalEditorType.CUSTOM))), externalEditor.isEqualTo(ExternalEditorType.CUSTOM))),

View file

@ -0,0 +1,19 @@
package io.xpipe.app.prefs;
import com.dlsc.formsfx.model.structure.Form;
import com.dlsc.preferencesfx.model.Category;
import com.dlsc.preferencesfx.model.PreferencesFxModel;
import com.dlsc.preferencesfx.view.CategoryView;
public class CustomCategoryView extends CategoryView {
public CustomCategoryView(PreferencesFxModel model, Category categoryModel) {
super(model, categoryModel);
}
public void initializeFormRenderer(Form form) {
getChildren().clear();
var preferencesFormRenderer = new CustomFormRenderer(form);
getChildren().add(preferencesFormRenderer);
}
}

View file

@ -0,0 +1,123 @@
package io.xpipe.app.prefs;
import com.dlsc.formsfx.model.structure.Element;
import com.dlsc.formsfx.model.structure.Field;
import com.dlsc.formsfx.model.structure.Form;
import com.dlsc.formsfx.model.structure.NodeElement;
import com.dlsc.preferencesfx.formsfx.view.controls.SimpleControl;
import com.dlsc.preferencesfx.formsfx.view.renderer.PreferencesFxFormRenderer;
import com.dlsc.preferencesfx.formsfx.view.renderer.PreferencesFxGroup;
import com.dlsc.preferencesfx.formsfx.view.renderer.PreferencesFxGroupRenderer;
import com.dlsc.preferencesfx.util.PreferencesFxUtils;
import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n;
import io.xpipe.extension.I18n;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import java.util.List;
import java.util.stream.Collectors;
public class CustomFormRenderer extends PreferencesFxFormRenderer {
public static final double SPACING = 8.0;
public CustomFormRenderer(Form form) {
super(form);
}
@Override
public void initializeParts() {
groups = form.getGroups().stream()
.map(group -> new PreferencesFxGroupRenderer((PreferencesFxGroup) group, this) {
@Override
public void initializeParts() {
super.initializeParts();
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public void layoutParts() {
StringBuilder styleClass = new StringBuilder("group");
// if there are no rows yet, getRowCount returns -1, in this case the next row is 0
int nextRow = PreferencesFxUtils.getRowCount(grid) + 1;
// Only when the preferencesGroup has a title
if (preferencesGroup.getTitle() != null) {
grid.add(titleLabel, 0, nextRow++, 2, 1);
titleLabel.getStyleClass().add("group-title");
AppFont.setSize(titleLabel, 2);
// Set margin for all but first group titles to visually separate groups
if (nextRow > 1) {
GridPane.setMargin(titleLabel, new Insets(SPACING * 3, 0, 0, 0));
}
}
List<Element> elements = preferencesGroup.getElements().stream()
.map(Element.class::cast)
.toList();
styleClass.append("-setting");
int rowAmount = nextRow;
for (int i = 0; i < elements.size(); i++) {
// add to GridPane
Element element = elements.get(i);
if (element instanceof Field f) {
var label = f.getLabel();
var descriptionKey = label != null ? label + "Description" : null;
SimpleControl c = (SimpleControl) ((Field) element).getRenderer();
c.setField((Field) element);
AppFont.header(c.getFieldLabel());
c.getFieldLabel().setPrefHeight(AppFont.getPixelSize(1));
c.getFieldLabel().setMaxHeight(AppFont.getPixelSize(1));
grid.add(c.getFieldLabel(), 0, i + rowAmount, 2, 1);
var descriptionLabel = new Label();
descriptionLabel.setWrapText(true);
descriptionLabel.disableProperty().bind(c.getFieldLabel().disabledProperty());
descriptionLabel.opacityProperty().bind(c.getFieldLabel().opacityProperty());
descriptionLabel.managedProperty().bind(c.getFieldLabel().managedProperty());
descriptionLabel.visibleProperty().bind(c.getFieldLabel().visibleProperty());
descriptionLabel.setMaxHeight(USE_PREF_SIZE);
if (AppI18n.get().containsKey(descriptionKey)) {
rowAmount++;
descriptionLabel.textProperty().bind(I18n.observable(descriptionKey));
grid.add(descriptionLabel, 0, i + rowAmount, 2, 1);
}
rowAmount++;
grid.add(c.getNode(), 0, i + rowAmount, 1, 1);
if (i == elements.size() - 1) {
// additional styling for the last setting
styleClass.append("-last");
}
var offset = preferencesGroup.getTitle() != null ? 15 : 0;
GridPane.setMargin(descriptionLabel, new Insets(SPACING, 0, 0, offset));
GridPane.setMargin(c.getNode(), new Insets(SPACING, 0, 0, offset));
if (!((i == 0) && (nextRow > 0))) {
GridPane.setMargin(c.getFieldLabel(), new Insets(SPACING * 3, 0, 0, offset));
} else {
GridPane.setMargin(c.getFieldLabel(), new Insets(SPACING, 0, 0, offset));
}
c.getFieldLabel().getStyleClass().add(styleClass.toString() + "-label");
c.getNode().getStyleClass().add(styleClass.toString() + "-node");
}
if (element instanceof NodeElement nodeElement) {
grid.add(nodeElement.getNode(), 0, i + rowAmount, GridPane.REMAINING, 1);
}
}
}
})
.collect(Collectors.toList());
}
}

View file

@ -80,7 +80,7 @@ public class XPipeDaemonProvider implements XPipeDaemon {
public <T extends Comp<?> & Validatable> T namedStoreChooser( public <T extends Comp<?> & Validatable> T namedStoreChooser(
ObservableValue<Predicate<DataStore>> filter, ObservableValue<Predicate<DataStore>> filter,
Property<? extends DataStore> selected, Property<? extends DataStore> selected,
DataStoreProvider.Category category) { DataStoreProvider.DataCategory category) {
return (T) new NamedStoreChoiceComp(filter, selected, category); return (T) new NamedStoreChoiceComp(filter, selected, category);
} }

View file

@ -34,12 +34,14 @@ none=None
save=Save save=Save
clean=Clean clean=Clean
refresh=Refresh refresh=Refresh
addDatabaseStore=Add Database ... addDatabase=Add Database ...
addDatabaseTitle=Add Database Store addHost=Add Host ...
addStreamStore=Add Stream ... addCommand=Add Command ...
addOther=Add Other ...
addStreamTitle=Add Stream Store addStreamTitle=Add Stream Store
selectQueryType=Query Type addConnection=Add Connection
selectQueryTypeDescription=Select Query Type selectType=Select Type
selectTypeDescription=Select connection type
selectDatabaseType=Database Type selectDatabaseType=Database Type
selectDatabaseTypeDescription=Select Type of the Database selectDatabaseTypeDescription=Select Type of the Database
selectShellType=Shell Type selectShellType=Shell Type

View file

@ -2,18 +2,26 @@ appearance=Appearance
integrations=Integrations integrations=Integrations
uiOptions=UI Options uiOptions=UI Options
theme=Theme theme=Theme
defaultProgram=Default Program editorProgram=Default Program
editorProgramDescription=The default text editor to use when editing any kind of text data.
useSystemFont=Use system font useSystemFont=Use system font
updates=Updates
advanced=Advanced
useSystemFontDescription=In case you're using a custom font on your system, you can opt to use it instead of the default X-Pipe font.
tooltipDelay=Tooltip delay tooltipDelay=Tooltip delay
tooltipDelayDescription=The amount of milliseconds to wait until a tooltip is displayed.
fontSize=Font size fontSize=Font size
windowOptions=Window Options windowOptions=Window Options
saveWindowLocation=Save window location on exit saveWindowLocation=Save window location
saveWindowLocationDescription=Controls whether the window coordinates should be saved and restored on restarts.
startupShutdown=Startup / Shutdown startupShutdown=Startup / Shutdown
system=System system=System
updateToPrereleases=Update to prereleases updateToPrereleases=Update to prereleases
updateToPrereleasesDescription=When enabled, the update check will also look for available prereleases in addition to full releases.
storage=Storage storage=Storage
runOnStartup=Run on startup runOnStartup=Run on startup
closeBehaviour=Close behaviour closeBehaviour=Close behaviour
closeBehaviourDescription=Controls how X-Pipe should proceed upon closing its main window.
language=Language language=Language
lightTheme=Light Theme lightTheme=Light Theme
darkTheme=Dark Theme darkTheme=Dark Theme
@ -23,6 +31,7 @@ minimizeToTray=Minimize to tray
closeBehaviourAlertTitle=Set closing behaviour closeBehaviourAlertTitle=Set closing behaviour
closeBehaviourAlertTitleHeader=Select what should happen when closing the window. closeBehaviourAlertTitleHeader=Select what should happen when closing the window.
externalStartupBehaviour=External startup behaviour externalStartupBehaviour=External startup behaviour
externalStartupBehaviourDescription=Controls the behavior of the desktop application when X-Pipe is started from for example the CLI or an API.
clearCachesAlertTitle=Clean Cache clearCachesAlertTitle=Clean Cache
clearCachesAlertTitleHeader=Do you want to clean all X-Pipe caches? clearCachesAlertTitleHeader=Do you want to clean all X-Pipe caches?
clearCachesAlertTitleContent=Note that this will delete all the data that is stored to improve the user experience, for example file usage histories. clearCachesAlertTitleContent=Note that this will delete all the data that is stored to improve the user experience, for example file usage histories.
@ -37,19 +46,34 @@ notAnAbsolutePath=Not an absolute path
notADirectory=Not a directory notADirectory=Not a directory
notAnEmptyDirectory=Not an empty directory notAnEmptyDirectory=Not an empty directory
automaticallyUpdate=Automatically update automaticallyUpdate=Automatically update
automaticallyUpdateDescription=When enabled, new releases are automatically downloaded in the background while X-Pipe is running and installed on the next launch.
sendAnonymousErrorReports=Send anonymous error reports sendAnonymousErrorReports=Send anonymous error reports
sendUsageStatistics=Send anonymous usage statistics sendUsageStatistics=Send anonymous usage statistics
storageDirectory=Storage directory storageDirectory=Storage directory
storageDirectoryDescription=The location where X-Pipe should store all connection and data source information.
logLevel=Log level logLevel=Log level
appBehaviour=Application behaviour
logLevelDescription=The log level that should be used when writing log files.
developerMode=Developer mode developerMode=Developer mode
developerModeDescription=When enabled, you will have access to a variety of additional options that are useful for development.
editor=Editor editor=Editor
custom=Custom custom=Custom
customEditorCommand=Custom editor command customEditorCommand=Custom editor command
customEditorCommandDescription=The command to use to open the custom editor. The placeholder string $file will be replaced by the quoted actual file name when called. If you don't specify a placeholder string, the actual filename will be appended.
editorReloadTimeout=Editor reload timeout editorReloadTimeout=Editor reload timeout
editorReloadTimeoutDescription=The amount of milliseconds to wait before reading a file after it has been updated. This avoids issues in cases where your editor is slow at writing or releasing file locks.
notepad++=Notepad++ notepad++=Notepad++
notepad++Windows=Notepad++ notepad++Windows=Notepad++
notepad++Linux=Notepad++ notepad++Linux=Notepad++
notepad=Notepad notepad=Notepad
developer=Developer developer=Developer
developerDisableUpdateVersionCheck=Disable Update Version Check developerDisableUpdateVersionCheck=Disable Update Version Check
developerDisableUpdateVersionCheckDescription=Controls whether the update checker will ignore the version number when looking for an update.
developerDisableGuiRestrictions=Disable GUI restrictions
developerDisableGuiRestrictionsDescription=Controls wether some disabled actions can still be executed from the user interface.
developerShowHiddenEntries=Show hidden entries
developerShowHiddenEntriesDescription=When enabled, hidden and internal data sources will be shown.
developerShowHiddenProviders=Show hidden providers
developerShowHiddenProvidersDescription=Controls whether hidden and internal connection and data source providers will be shown in the creation dialog.
developerDisableConnectorInstallationVersionCheck=Disable Connector Version Check developerDisableConnectorInstallationVersionCheck=Disable Connector Version Check
developerDisableConnectorInstallationVersionCheckDescription=Controls whether the update checker will ignore the version number when inspecting the version of an X-Pipe connector installed on a remote machine.

2
dist/changelogs/0.4.30.md vendored Normal file
View file

@ -0,0 +1,2 @@
- Improve settings menu layout
- Improve connection creation sections

View file

@ -71,8 +71,8 @@ public class InMemoryStoreProvider implements DataStoreProvider {
} }
@Override @Override
public Category getCategory() { public DataCategory getCategory() {
return Category.STREAM; return DataCategory.STREAM;
} }
@Override @Override

View file

@ -30,7 +30,7 @@ public class RawFileOutputTarget implements DataSourceTarget {
new SimpleObjectProperty<>(store -> store instanceof StreamDataStore new SimpleObjectProperty<>(store -> store instanceof StreamDataStore
&& (store.getFlow().hasOutput())), && (store.getFlow().hasOutput())),
target, target,
DataStoreProvider.Category.STREAM); DataStoreProvider.DataCategory.STREAM);
storeChoice storeChoice
.apply(GrowAugment.create(true, true)) .apply(GrowAugment.create(true, true))
.apply(struc -> GridPane.setVgrow(struc.get(), Priority.ALWAYS)); .apply(struc -> GridPane.setVgrow(struc.get(), Priority.ALWAYS));

View file

@ -26,19 +26,30 @@ public interface DataStoreProvider {
} }
} }
default Category getCategory() { default DataCategory getCategory() {
var c = getStoreClasses().get(0); var c = getStoreClasses().get(0);
if (StreamDataStore.class.isAssignableFrom(c)) { if (StreamDataStore.class.isAssignableFrom(c)) {
return Category.STREAM; return DataCategory.STREAM;
} }
if (FileSystemStore.class.isAssignableFrom(c) || ShellStore.class.isAssignableFrom(c)) { if (FileSystemStore.class.isAssignableFrom(c) || ShellStore.class.isAssignableFrom(c)) {
return Category.SHELL; return DataCategory.SHELL;
} }
throw new ExtensionException("Provider " + getId() + " has no set category"); throw new ExtensionException("Provider " + getId() + " has no set category");
} }
default DisplayCategory getDisplayCategory() {
var category = getCategory();
if (category.equals(DataCategory.SHELL)) {
return DisplayCategory.HOST;
}
if (category.equals(DataCategory.DATABASE)) {
return DisplayCategory.DATABASE;
}
return DisplayCategory.OTHER;
}
default DataStore getParent(DataStore store) { default DataStore getParent(DataStore store) {
return null; return null;
} }
@ -105,9 +116,16 @@ public interface DataStoreProvider {
return true; return true;
} }
enum Category { enum DataCategory {
STREAM, STREAM,
SHELL, SHELL,
DATABASE; DATABASE;
} }
enum DisplayCategory {
HOST,
DATABASE,
COMMAND,
OTHER;
}
} }

View file

@ -47,7 +47,7 @@ public interface XPipeDaemon {
<T extends Comp<?> & Validatable> T namedStoreChooser( <T extends Comp<?> & Validatable> T namedStoreChooser(
ObservableValue<Predicate<DataStore>> filter, ObservableValue<Predicate<DataStore>> filter,
Property<? extends DataStore> selected, Property<? extends DataStore> selected,
DataStoreProvider.Category category); DataStoreProvider.DataCategory category);
<T extends Comp<?> & Validatable> T namedSourceChooser( <T extends Comp<?> & Validatable> T namedSourceChooser(
ObservableValue<Predicate<DataSource<?>>> filter, ObservableValue<Predicate<DataSource<?>>> filter,

Binary file not shown.

View file

@ -1 +1 @@
0.4.29 0.4.30