mirror of
https://github.com/xpipe-io/xpipe.git
synced 2025-04-15 16:53:34 +00:00
Improve settings menu and connection creation [release]
This commit is contained in:
parent
28a8c95c71
commit
287f3d084d
25 changed files with 304 additions and 74 deletions
|
@ -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-javafx', 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: 'org.slf4j', name: 'slf4j-api', version: '2.0.0'
|
||||
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", "com.dustinredmond.fxtrayicon/com.dustinredmond.fxtrayicon=io.xpipe.app",
|
||||
"--add-opens", "net.synedra.validatorfx/net.synedra.validatorfx=io.xpipe.extension",
|
||||
"--add-opens", 'com.dlsc.preferencesfx/com.dlsc.preferencesfx.view=io.xpipe.app',
|
||||
"-Xmx8g",
|
||||
"--enable-preview",
|
||||
// "-XX:+ExitOnOutOfMemoryError",
|
||||
|
|
|
@ -22,7 +22,7 @@ import lombok.experimental.FieldDefaults;
|
|||
@AllArgsConstructor
|
||||
public class DataStoreSelectorComp extends Comp<CompStructure<Button>> {
|
||||
|
||||
DataStoreProvider.Category category;
|
||||
DataStoreProvider.DataCategory category;
|
||||
Property<DataStore> chosenStore;
|
||||
|
||||
@Override
|
||||
|
@ -30,7 +30,7 @@ public class DataStoreSelectorComp extends Comp<CompStructure<Button>> {
|
|||
var button = new JFXButton();
|
||||
button.setGraphic(getGraphic());
|
||||
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());
|
||||
});
|
||||
e.consume();
|
||||
|
|
|
@ -32,7 +32,7 @@ public class DsDbStoreChooserComp extends SimpleComp {
|
|||
var filter = Bindings.createObjectBinding(
|
||||
() -> (Predicate<DataStoreEntry>) e -> {
|
||||
if (provider.getValue() == null) {
|
||||
return e.getProvider().getCategory() == DataStoreProvider.Category.DATABASE;
|
||||
return e.getProvider().getCategory() == DataStoreProvider.DataCategory.DATABASE;
|
||||
}
|
||||
|
||||
return provider.getValue().couldSupportStore(e.getStore());
|
||||
|
@ -42,7 +42,7 @@ public class DsDbStoreChooserComp extends SimpleComp {
|
|||
var connections = new TabPaneComp.Entry(
|
||||
I18n.observable("savedConnections"),
|
||||
"mdi2m-monitor",
|
||||
NamedStoreChoiceComp.create(filter, input, DataStoreProvider.Category.DATABASE)
|
||||
NamedStoreChoiceComp.create(filter, input, DataStoreProvider.DataCategory.DATABASE)
|
||||
.styleClass("store-local-file-chooser"));
|
||||
|
||||
var pane = new TabPaneComp(new SimpleObjectProperty<>(connections), List.of(connections));
|
||||
|
|
|
@ -18,28 +18,23 @@ import lombok.AllArgsConstructor;
|
|||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
@AllArgsConstructor
|
||||
public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>>> {
|
||||
|
||||
DataStoreProvider.Category type;
|
||||
Predicate<DataStoreProvider> filter;
|
||||
Property<DataStoreProvider> provider;
|
||||
|
||||
private Region createDefaultNode() {
|
||||
return switch (type) {
|
||||
case STREAM -> JfxHelper.createNamedEntry(
|
||||
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");
|
||||
};
|
||||
return JfxHelper.createNamedEntry(
|
||||
I18n.get("selectType"), I18n.get("selectTypeDescription"), "machine_icon.png");
|
||||
}
|
||||
|
||||
private List<DataStoreProvider> getProviders() {
|
||||
return DataStoreProviders.getAll().stream()
|
||||
.filter(p -> p.getCategory() == type)
|
||||
.filter(filter)
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
|
|
@ -114,14 +114,14 @@ public class DsStreamStoreChoiceComp extends SimpleComp implements Validatable {
|
|||
var named = new TabPaneComp.Entry(
|
||||
I18n.observable("stored"),
|
||||
"mdrmz-storage",
|
||||
NamedStoreChoiceComp.create(filter, namedStore, DataStoreProvider.Category.STREAM));
|
||||
NamedStoreChoiceComp.create(filter, namedStore, DataStoreProvider.DataCategory.STREAM));
|
||||
|
||||
var otherStore = new SimpleObjectProperty<DataStore>(
|
||||
localStore.get() == null && remoteStore.get() == null && !isNamedStore ? selected.getValue() : null);
|
||||
var other = new TabPaneComp.Entry(
|
||||
I18n.observable("other"),
|
||||
"mdrmz-web_asset",
|
||||
new DataStoreSelectorComp(DataStoreProvider.Category.STREAM, otherStore));
|
||||
new DataStoreSelectorComp(DataStoreProvider.DataCategory.STREAM, otherStore));
|
||||
|
||||
var selectedTab = new SimpleObjectProperty<TabPaneComp.Entry>();
|
||||
if (localStore.get() != null) {
|
||||
|
|
|
@ -37,6 +37,7 @@ import lombok.experimental.FieldDefaults;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||
|
@ -44,7 +45,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
MultiStepComp parent;
|
||||
Property<DataStoreProvider> provider;
|
||||
Property<DataStore> input;
|
||||
DataStoreProvider.Category generalType;
|
||||
Predicate<DataStoreProvider> filter;
|
||||
BooleanProperty busy = new SimpleBooleanProperty();
|
||||
Property<Validator> validator = new SimpleObjectProperty<>(new SimpleValidator());
|
||||
Property<String> messageProp = new SimpleStringProperty();
|
||||
|
@ -58,13 +59,13 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
MultiStepComp parent,
|
||||
Property<DataStoreProvider> provider,
|
||||
Property<DataStore> input,
|
||||
DataStoreProvider.Category generalType,
|
||||
Predicate<DataStoreProvider> filter,
|
||||
String initialName) {
|
||||
super(null);
|
||||
this.parent = parent;
|
||||
this.provider = provider;
|
||||
this.input = input;
|
||||
this.generalType = generalType;
|
||||
this.filter = filter;
|
||||
this.name = new SimpleStringProperty(initialName);
|
||||
this.input.addListener((c, o, n) -> {
|
||||
changedSinceError.setValue(true);
|
||||
|
@ -88,7 +89,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
}
|
||||
|
||||
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(() -> {
|
||||
e.applyChanges(newE);
|
||||
if (!DataStorage.get().getStores().contains(e)) {
|
||||
|
@ -99,9 +100,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
});
|
||||
}
|
||||
|
||||
public static void showCreation(DataStoreProvider.Category cat) {
|
||||
|
||||
show(null, null, null, cat, e -> {
|
||||
public static void showCreation(Predicate<DataStoreProvider> filter) {
|
||||
show(null, null, null, filter, e -> {
|
||||
try {
|
||||
DataStorage.get().addStore(e);
|
||||
} catch (Exception ex) {
|
||||
|
@ -114,13 +114,11 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
String initialName,
|
||||
DataStoreProvider provider,
|
||||
DataStore s,
|
||||
DataStoreProvider.Category cat,
|
||||
Predicate<DataStoreProvider> filter,
|
||||
Consumer<DataStoreEntry> con) {
|
||||
var prop = new SimpleObjectProperty<DataStoreProvider>(provider);
|
||||
var store = new SimpleObjectProperty<DataStore>(s);
|
||||
var name = cat == DataStoreProvider.Category.SHELL
|
||||
? "addShellTitle"
|
||||
: cat == DataStoreProvider.Category.DATABASE ? "addDatabaseTitle" : "addStreamTitle";
|
||||
var name = "addConnection";
|
||||
Platform.runLater(() -> {
|
||||
var stage = AppWindowHelper.sideWindow(
|
||||
I18n.get(name),
|
||||
|
@ -128,7 +126,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
return new MultiStepComp() {
|
||||
|
||||
private final GuiDsStoreCreator creator =
|
||||
new GuiDsStoreCreator(this, prop, store, cat, initialName);
|
||||
new GuiDsStoreCreator(this, prop, store, filter, initialName);
|
||||
|
||||
@Override
|
||||
protected List<Entry> setup() {
|
||||
|
@ -182,7 +180,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
@Override
|
||||
public CompStructure<? extends Region> createBase() {
|
||||
var layout = new BorderPane();
|
||||
var providerChoice = new DsStoreProviderChoiceComp(generalType, provider);
|
||||
var providerChoice = new DsStoreProviderChoiceComp(filter, provider);
|
||||
providerChoice.apply(GrowAugment.create(true, false));
|
||||
|
||||
SimpleChangeListener.apply(provider, n -> {
|
||||
|
|
|
@ -41,7 +41,7 @@ import java.util.function.Predicate;
|
|||
public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
|
||||
|
||||
private final ObservableValue<Predicate<DataStore>> filter;
|
||||
private final DataStoreProvider.Category category;
|
||||
private final DataStoreProvider.DataCategory category;
|
||||
private final Property<? extends DataStore> selected;
|
||||
private final StringProperty filterString = new SimpleStringProperty();
|
||||
|
||||
|
@ -53,7 +53,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
|
|||
public NamedStoreChoiceComp(
|
||||
ObservableValue<Predicate<DataStore>> filter,
|
||||
Property<? extends DataStore> selected,
|
||||
DataStoreProvider.Category category) {
|
||||
DataStoreProvider.DataCategory category) {
|
||||
this.filter = filter;
|
||||
this.selected = selected;
|
||||
this.category = category;
|
||||
|
@ -63,7 +63,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
|
|||
public static NamedStoreChoiceComp create(
|
||||
ObservableValue<Predicate<DataStoreEntry>> filter,
|
||||
Property<? extends DataStore> selected,
|
||||
DataStoreProvider.Category category) {
|
||||
DataStoreProvider.DataCategory category) {
|
||||
return new NamedStoreChoiceComp(
|
||||
Bindings.createObjectBinding(
|
||||
() -> {
|
||||
|
@ -142,7 +142,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
|
|||
var text = new LabelComp(I18n.observable("noMatchingStoreFound"))
|
||||
.apply(struc -> VBox.setVgrow(struc.get(), Priority.ALWAYS));
|
||||
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))
|
||||
.apply(struc -> {
|
||||
|
|
|
@ -20,28 +20,35 @@ public class StoreCreationBarComp extends SimpleComp {
|
|||
|
||||
@Override
|
||||
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(
|
||||
I18n.observable("addStreamStore"), new FontIcon("mdi2c-card-plus-outline"), () -> {
|
||||
GuiDsStoreCreator.showCreation(DataStoreProvider.Category.STREAM);
|
||||
I18n.observable("addCommand"), new FontIcon("mdi2c-code-greater-than"), () -> {
|
||||
GuiDsStoreCreator.showCreation(v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.COMMAND));
|
||||
})
|
||||
.shortcut(new KeyCodeCombination(KeyCode.L, KeyCombination.SHORTCUT_DOWN))
|
||||
.apply(new FancyTooltipAugment<>("addStreamStore"));
|
||||
.shortcut(new KeyCodeCombination(KeyCode.C, KeyCombination.SHORTCUT_DOWN))
|
||||
.apply(new FancyTooltipAugment<>("addCommand"));
|
||||
|
||||
var newShellStore = new ButtonComp(
|
||||
I18n.observable("addShellStore"), new FontIcon("mdi2h-home-plus-outline"), () -> {
|
||||
GuiDsStoreCreator.showCreation(DataStoreProvider.Category.SHELL);
|
||||
I18n.observable("addHost"), new FontIcon("mdi2h-home-plus-outline"), () -> {
|
||||
GuiDsStoreCreator.showCreation(v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.HOST));
|
||||
})
|
||||
.shortcut(new KeyCodeCombination(KeyCode.M, KeyCombination.SHORTCUT_DOWN))
|
||||
.apply(new FancyTooltipAugment<>("addShellStore"));
|
||||
.shortcut(new KeyCodeCombination(KeyCode.H, KeyCombination.SHORTCUT_DOWN))
|
||||
.apply(new FancyTooltipAugment<>("addHost"));
|
||||
|
||||
var newDbStore = new ButtonComp(
|
||||
I18n.observable("addDatabaseStore"), new FontIcon("mdi2d-database-plus-outline"), () -> {
|
||||
GuiDsStoreCreator.showCreation(DataStoreProvider.Category.DATABASE);
|
||||
I18n.observable("addDatabase"), new FontIcon("mdi2d-database-plus-outline"), () -> {
|
||||
GuiDsStoreCreator.showCreation(v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.DATABASE));
|
||||
})
|
||||
.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()));
|
||||
var bar = box.createRegion();
|
||||
bar.getStyleClass().add("bar");
|
||||
|
|
|
@ -254,7 +254,7 @@ public class AppExtensionManager {
|
|||
extendedLayer =
|
||||
ModuleLayer.defineModulesWithOneLoader(cf, extended, scl).layer();
|
||||
} else {
|
||||
extendedLayer = ModuleLayer.boot();
|
||||
extendedLayer = baseLayer;
|
||||
}
|
||||
|
||||
addNativeLibrariesToPath();
|
||||
|
|
|
@ -135,6 +135,15 @@ public class AppI18n implements I18n {
|
|||
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) {
|
||||
var key = getKey(s);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange
|
|||
|
||||
@Override
|
||||
public Response handleRequest(BeaconHandler handler, Request msg) throws Exception {
|
||||
var categories = DataStoreProvider.Category.values();
|
||||
var categories = DataStoreProvider.DataCategory.values();
|
||||
var all = DataStoreProviders.getAll();
|
||||
var map = Arrays.stream(categories)
|
||||
.collect(Collectors.toMap(category -> getName(category), category -> all.stream()
|
||||
|
@ -31,7 +31,7 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange
|
|||
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()
|
||||
+ category.name().substring(1).toLowerCase();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.app.prefs;
|
||||
|
||||
import com.dlsc.formsfx.model.structure.Form;
|
||||
import com.dlsc.formsfx.model.util.TranslationService;
|
||||
import com.dlsc.preferencesfx.PreferencesFxEvent;
|
||||
import com.dlsc.preferencesfx.history.History;
|
||||
|
@ -11,6 +12,8 @@ import com.dlsc.preferencesfx.view.*;
|
|||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.event.EventType;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -56,10 +59,20 @@ public class AppPreferencesFx {
|
|||
public void setupControls() {
|
||||
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);
|
||||
|
||||
categoryController = new CategoryController();
|
||||
categoryController.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
categoryController.setFitToWidth(true);
|
||||
initializeCategoryViews();
|
||||
|
||||
// display initial category
|
||||
|
@ -88,9 +101,24 @@ public class AppPreferencesFx {
|
|||
*/
|
||||
private void initializeCategoryViews() {
|
||||
preferencesFxModel.getFlatCategoriesLst().forEach(category -> {
|
||||
CategoryView categoryView = new CategoryView(preferencesFxModel, category);
|
||||
var categoryView = new CustomCategoryView(preferencesFxModel, category);
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -402,17 +402,22 @@ public class AppPrefs {
|
|||
Category.of(
|
||||
"system",
|
||||
Group.of(
|
||||
"appBehaviour",
|
||||
Setting.of(
|
||||
"externalStartupBehaviour",
|
||||
externalStartupBehaviourControl,
|
||||
externalStartupBehaviour),
|
||||
Setting.of("closeBehaviour", closeBehaviourControl, closeBehaviour),
|
||||
Setting.of("closeBehaviour", closeBehaviourControl, closeBehaviour)),
|
||||
Group.of(
|
||||
"updates",
|
||||
Setting.of("automaticallyUpdate", automaticallyUpdateField, automaticallyUpdate)
|
||||
.applyVisibility(VisibilityProperty.of(new SimpleBooleanProperty(
|
||||
XPipeDistributionType.get().supportsUpdate()))),
|
||||
Setting.of("updateToPrereleases", updateToPrereleasesField, updateToPrereleases)
|
||||
.applyVisibility(VisibilityProperty.of(new SimpleBooleanProperty(
|
||||
XPipeDistributionType.get().supportsUpdate()))),
|
||||
XPipeDistributionType.get().supportsUpdate())))),
|
||||
Group.of(
|
||||
"advanced",
|
||||
Setting.of("storageDirectory", storageDirectoryControl, internalStorageDirectory),
|
||||
Setting.of("logLevel", logLevelField, internalLogLevel),
|
||||
Setting.of("developerMode", developerModeField, internalDeveloperMode))),
|
||||
|
@ -423,14 +428,13 @@ public class AppPrefs {
|
|||
Setting.of("language", languageControl, languageInternal),
|
||||
Setting.of("theme", themeControl, themeInternal),
|
||||
Setting.of("useSystemFont", useSystemFontInternal),
|
||||
Setting.of("tooltipDelay", tooltipDelayInternal, tooltipDelayMin, tooltipDelayMax),
|
||||
Setting.of("fontSize", fontSizeInternal, fontSizeMin, fontSizeMax)),
|
||||
Setting.of("tooltipDelay", tooltipDelayInternal, tooltipDelayMin, tooltipDelayMax)),
|
||||
Group.of("windowOptions", Setting.of("saveWindowLocation", saveWindowLocationInternal))),
|
||||
Category.of(
|
||||
"integrations",
|
||||
Group.of(
|
||||
"editor",
|
||||
Setting.of("defaultProgram", externalEditorControl, externalEditor),
|
||||
Setting.of("editorProgram", externalEditorControl, externalEditor),
|
||||
Setting.of("customEditorCommand", customEditorCommandControl, customEditorCommand)
|
||||
.applyVisibility(VisibilityProperty.of(
|
||||
externalEditor.isEqualTo(ExternalEditorType.CUSTOM))),
|
||||
|
|
19
app/src/main/java/io/xpipe/app/prefs/CustomCategoryView.java
Normal file
19
app/src/main/java/io/xpipe/app/prefs/CustomCategoryView.java
Normal 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);
|
||||
}
|
||||
}
|
123
app/src/main/java/io/xpipe/app/prefs/CustomFormRenderer.java
Normal file
123
app/src/main/java/io/xpipe/app/prefs/CustomFormRenderer.java
Normal 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());
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ public class XPipeDaemonProvider implements XPipeDaemon {
|
|||
public <T extends Comp<?> & Validatable> T namedStoreChooser(
|
||||
ObservableValue<Predicate<DataStore>> filter,
|
||||
Property<? extends DataStore> selected,
|
||||
DataStoreProvider.Category category) {
|
||||
DataStoreProvider.DataCategory category) {
|
||||
return (T) new NamedStoreChoiceComp(filter, selected, category);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,12 +34,14 @@ none=None
|
|||
save=Save
|
||||
clean=Clean
|
||||
refresh=Refresh
|
||||
addDatabaseStore=Add Database ...
|
||||
addDatabaseTitle=Add Database Store
|
||||
addStreamStore=Add Stream ...
|
||||
addDatabase=Add Database ...
|
||||
addHost=Add Host ...
|
||||
addCommand=Add Command ...
|
||||
addOther=Add Other ...
|
||||
addStreamTitle=Add Stream Store
|
||||
selectQueryType=Query Type
|
||||
selectQueryTypeDescription=Select Query Type
|
||||
addConnection=Add Connection
|
||||
selectType=Select Type
|
||||
selectTypeDescription=Select connection type
|
||||
selectDatabaseType=Database Type
|
||||
selectDatabaseTypeDescription=Select Type of the Database
|
||||
selectShellType=Shell Type
|
||||
|
|
|
@ -2,18 +2,26 @@ appearance=Appearance
|
|||
integrations=Integrations
|
||||
uiOptions=UI Options
|
||||
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
|
||||
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
|
||||
tooltipDelayDescription=The amount of milliseconds to wait until a tooltip is displayed.
|
||||
fontSize=Font size
|
||||
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
|
||||
system=System
|
||||
updateToPrereleases=Update to prereleases
|
||||
updateToPrereleasesDescription=When enabled, the update check will also look for available prereleases in addition to full releases.
|
||||
storage=Storage
|
||||
runOnStartup=Run on startup
|
||||
closeBehaviour=Close behaviour
|
||||
closeBehaviourDescription=Controls how X-Pipe should proceed upon closing its main window.
|
||||
language=Language
|
||||
lightTheme=Light Theme
|
||||
darkTheme=Dark Theme
|
||||
|
@ -23,6 +31,7 @@ minimizeToTray=Minimize to tray
|
|||
closeBehaviourAlertTitle=Set closing behaviour
|
||||
closeBehaviourAlertTitleHeader=Select what should happen when closing the window.
|
||||
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
|
||||
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.
|
||||
|
@ -37,19 +46,34 @@ notAnAbsolutePath=Not an absolute path
|
|||
notADirectory=Not a directory
|
||||
notAnEmptyDirectory=Not an empty directory
|
||||
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
|
||||
sendUsageStatistics=Send anonymous usage statistics
|
||||
storageDirectory=Storage directory
|
||||
storageDirectoryDescription=The location where X-Pipe should store all connection and data source information.
|
||||
logLevel=Log level
|
||||
appBehaviour=Application behaviour
|
||||
logLevelDescription=The log level that should be used when writing log files.
|
||||
developerMode=Developer mode
|
||||
developerModeDescription=When enabled, you will have access to a variety of additional options that are useful for development.
|
||||
editor=Editor
|
||||
custom=Custom
|
||||
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
|
||||
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++Windows=Notepad++
|
||||
notepad++Linux=Notepad++
|
||||
notepad=Notepad
|
||||
developer=Developer
|
||||
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
|
||||
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
2
dist/changelogs/0.4.30.md
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
- Improve settings menu layout
|
||||
- Improve connection creation sections
|
|
@ -71,8 +71,8 @@ public class InMemoryStoreProvider implements DataStoreProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Category getCategory() {
|
||||
return Category.STREAM;
|
||||
public DataCategory getCategory() {
|
||||
return DataCategory.STREAM;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,7 +30,7 @@ public class RawFileOutputTarget implements DataSourceTarget {
|
|||
new SimpleObjectProperty<>(store -> store instanceof StreamDataStore
|
||||
&& (store.getFlow().hasOutput())),
|
||||
target,
|
||||
DataStoreProvider.Category.STREAM);
|
||||
DataStoreProvider.DataCategory.STREAM);
|
||||
storeChoice
|
||||
.apply(GrowAugment.create(true, true))
|
||||
.apply(struc -> GridPane.setVgrow(struc.get(), Priority.ALWAYS));
|
||||
|
|
|
@ -26,19 +26,30 @@ public interface DataStoreProvider {
|
|||
}
|
||||
}
|
||||
|
||||
default Category getCategory() {
|
||||
default DataCategory getCategory() {
|
||||
var c = getStoreClasses().get(0);
|
||||
if (StreamDataStore.class.isAssignableFrom(c)) {
|
||||
return Category.STREAM;
|
||||
return DataCategory.STREAM;
|
||||
}
|
||||
|
||||
if (FileSystemStore.class.isAssignableFrom(c) || ShellStore.class.isAssignableFrom(c)) {
|
||||
return Category.SHELL;
|
||||
return DataCategory.SHELL;
|
||||
}
|
||||
|
||||
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) {
|
||||
return null;
|
||||
}
|
||||
|
@ -105,9 +116,16 @@ public interface DataStoreProvider {
|
|||
return true;
|
||||
}
|
||||
|
||||
enum Category {
|
||||
enum DataCategory {
|
||||
STREAM,
|
||||
SHELL,
|
||||
DATABASE;
|
||||
}
|
||||
|
||||
enum DisplayCategory {
|
||||
HOST,
|
||||
DATABASE,
|
||||
COMMAND,
|
||||
OTHER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public interface XPipeDaemon {
|
|||
<T extends Comp<?> & Validatable> T namedStoreChooser(
|
||||
ObservableValue<Predicate<DataStore>> filter,
|
||||
Property<? extends DataStore> selected,
|
||||
DataStoreProvider.Category category);
|
||||
DataStoreProvider.DataCategory category);
|
||||
|
||||
<T extends Comp<?> & Validatable> T namedSourceChooser(
|
||||
ObservableValue<Predicate<DataSource<?>>> filter,
|
||||
|
|
BIN
gradle/gradle_scripts/preferencesfx-core-11.15.0.jar
Normal file
BIN
gradle/gradle_scripts/preferencesfx-core-11.15.0.jar
Normal file
Binary file not shown.
2
version
2
version
|
@ -1 +1 @@
|
|||
0.4.29
|
||||
0.4.30
|
Loading…
Add table
Reference in a new issue