This commit is contained in:
crschnick 2023-02-08 14:34:32 +00:00
parent 8b4a59e8f0
commit 84d0a70ec8
61 changed files with 324 additions and 382 deletions

View file

@ -2,7 +2,7 @@ package io.xpipe.app.comp.about;
import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.core.AppLogs; import io.xpipe.app.core.AppLogs;
import io.xpipe.app.editor.EditorState; import io.xpipe.app.util.ExternalEditor;
import io.xpipe.app.issue.UserReportComp; import io.xpipe.app.issue.UserReportComp;
import io.xpipe.core.util.XPipeInstallation; import io.xpipe.core.util.XPipeInstallation;
import io.xpipe.extension.I18n; import io.xpipe.extension.I18n;
@ -30,7 +30,7 @@ public class BrowseDirectoryComp extends SimpleComp {
.addComp( .addComp(
"logFile", "logFile",
new ButtonComp(I18n.observable("openCurrentLogFile"), () -> { new ButtonComp(I18n.observable("openCurrentLogFile"), () -> {
EditorState.get().openInEditor(AppLogs.get().getSessionLogsDirectory().resolve("xpipe.log").toString()); ExternalEditor.get().openInEditor(AppLogs.get().getSessionLogsDirectory().resolve("xpipe.log").toString());
}), }),
null) null)
.addComp( .addComp(

View file

@ -2,7 +2,7 @@ package io.xpipe.app.comp.about;
import io.xpipe.extension.util.XPipeDistributionType; import io.xpipe.extension.util.XPipeDistributionType;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.grid.AppUpdater; import io.xpipe.app.update.AppUpdater;
import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.Hyperlinks;
import io.xpipe.extension.I18n; import io.xpipe.extension.I18n;
import io.xpipe.extension.fxcomps.SimpleComp; import io.xpipe.extension.fxcomps.SimpleComp;

View file

@ -1,6 +1,6 @@
package io.xpipe.app.comp.base; package io.xpipe.app.comp.base;
import io.xpipe.app.editor.EditorState; import io.xpipe.app.util.ExternalEditor;
import io.xpipe.extension.fxcomps.Comp; import io.xpipe.extension.fxcomps.Comp;
import io.xpipe.extension.fxcomps.SimpleComp; import io.xpipe.extension.fxcomps.SimpleComp;
import io.xpipe.extension.fxcomps.impl.IconButtonComp; import io.xpipe.extension.fxcomps.impl.IconButtonComp;
@ -45,7 +45,7 @@ public class IntegratedTextAreaComp extends SimpleComp {
} }
private Region createOpenButton(Region container) { private Region createOpenButton(Region container) {
var button = new IconButtonComp("mdal-edit", () -> EditorState.get() var button = new IconButtonComp("mdal-edit", () -> ExternalEditor.get()
.startEditing(identifier, fileType, this, value.getValue(), (s) -> { .startEditing(identifier, fileType, this, value.getValue(), (s) -> {
Platform.runLater(() -> value.setValue(s)); Platform.runLater(() -> value.setValue(s));
})).createRegion(); })).createRegion();

View file

@ -3,7 +3,6 @@ package io.xpipe.app.comp.source;
import io.xpipe.app.comp.base.MultiStepComp; import io.xpipe.app.comp.base.MultiStepComp;
import io.xpipe.app.comp.source.store.DsDbStoreChooserComp; import io.xpipe.app.comp.source.store.DsDbStoreChooserComp;
import io.xpipe.app.comp.source.store.DsStreamStoreChoiceComp; import io.xpipe.app.comp.source.store.DsStreamStoreChoiceComp;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.core.source.DataSource; import io.xpipe.core.source.DataSource;
import io.xpipe.core.store.DataStore; import io.xpipe.core.store.DataStore;
import io.xpipe.extension.DataSourceProvider; import io.xpipe.extension.DataSourceProvider;
@ -42,7 +41,7 @@ public class GuiDsStoreSelectStep extends MultiStepComp.Step<CompStructure<? ext
DataSourceProvider.Category category, DataSourceProvider.Category category,
ObjectProperty<? extends DataSource<?>> baseSource, ObjectProperty<? extends DataSource<?>> baseSource,
BooleanProperty loading) { BooleanProperty loading) {
super(Hyperlinks.openLink(Hyperlinks.DOCS_DATA_INPUT)); super(null);
this.parent = parent; this.parent = parent;
this.provider = provider; this.provider = provider;
this.input = input; this.input = input;

View file

@ -33,12 +33,15 @@ public class SourceEntryContextMenu<S extends CompStructure<?>> extends PopupMen
AppFont.normal(cm.getStyleableNode()); AppFont.normal(cm.getStyleableNode());
for (var actionProvider : entry.getActionProviders()) { for (var actionProvider : entry.getActionProviders()) {
var name = actionProvider.getName(entry.getEntry().getSource().asNeeded()); var c = actionProvider.getDataSourceCallSite();
var icon = actionProvider.getIcon(entry.getEntry().getSource().asNeeded()); var name = c.getName(entry.getEntry().getSource().asNeeded());
var icon = c.getIcon(entry.getEntry().getSource().asNeeded());
var item = new MenuItem(null, new FontIcon(icon)); var item = new MenuItem(null, new FontIcon(icon));
item.setOnAction(event -> { item.setOnAction(event -> {
event.consume();
try { try {
actionProvider.execute(entry.getEntry().getSource().asNeeded()); var action = c.createAction(entry.getEntry().getSource().asNeeded());
action.execute();
} catch (Exception e) { } catch (Exception e) {
ErrorEvent.fromThrowable(e).handle(); ErrorEvent.fromThrowable(e).handle();
} }

View file

@ -4,16 +4,17 @@ import io.xpipe.app.comp.source.GuiDsCreatorMultiStep;
import io.xpipe.app.comp.storage.StorageFilter; import io.xpipe.app.comp.storage.StorageFilter;
import io.xpipe.app.comp.storage.collection.SourceCollectionViewState; import io.xpipe.app.comp.storage.collection.SourceCollectionViewState;
import io.xpipe.app.comp.storage.collection.SourceCollectionWrapper; import io.xpipe.app.comp.storage.collection.SourceCollectionWrapper;
import io.xpipe.app.storage.*; import io.xpipe.app.storage.DataSourceEntry;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.StorageElement;
import io.xpipe.core.source.DataSource; import io.xpipe.core.source.DataSource;
import io.xpipe.core.store.DataFlow; import io.xpipe.core.store.DataFlow;
import io.xpipe.extension.DataSourceActionProvider;
import io.xpipe.extension.DataStoreProviders; import io.xpipe.extension.DataStoreProviders;
import io.xpipe.extension.I18n; import io.xpipe.extension.I18n;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;
import io.xpipe.extension.fxcomps.util.PlatformThread; import io.xpipe.extension.fxcomps.util.PlatformThread;
import io.xpipe.extension.util.ActionProvider;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.collections.FXCollections;
import lombok.Value; import lombok.Value;
import java.time.Instant; import java.time.Instant;
@ -29,13 +30,10 @@ public class SourceEntryWrapper implements StorageFilter.Filterable {
StringProperty information = new SimpleStringProperty(); StringProperty information = new SimpleStringProperty();
StringProperty storeSummary = new SimpleStringProperty(); StringProperty storeSummary = new SimpleStringProperty();
Property<Instant> lastUsed = new SimpleObjectProperty<>(); Property<Instant> lastUsed = new SimpleObjectProperty<>();
Property<AccessMode> accessMode = new SimpleObjectProperty<>();
Property<DataFlow> dataFlow = new SimpleObjectProperty<>(); Property<DataFlow> dataFlow = new SimpleObjectProperty<>();
ObjectProperty<DataSourceEntry.State> state = new SimpleObjectProperty<>(); ObjectProperty<DataSourceEntry.State> state = new SimpleObjectProperty<>();
BooleanProperty loading = new SimpleBooleanProperty(); BooleanProperty loading = new SimpleBooleanProperty();
List<ActionProvider> actionProviders = new ArrayList<>();
List<DataSourceActionProvider<?>> actionProviders = new ArrayList<>();
ListProperty<ApplicationAccess> accesses = new SimpleListProperty<>(FXCollections.observableArrayList());
public SourceEntryWrapper(DataSourceEntry entry) { public SourceEntryWrapper(DataSourceEntry entry) {
this.entry = entry; this.entry = entry;
@ -100,16 +98,21 @@ public class SourceEntryWrapper implements StorageFilter.Filterable {
loading.setValue(entry.getState() == null || entry.getState() == DataSourceEntry.State.VALIDATING); loading.setValue(entry.getState() == null || entry.getState() == DataSourceEntry.State.VALIDATING);
actionProviders.clear(); actionProviders.clear();
actionProviders.addAll(DataSourceActionProvider.ALL.stream() actionProviders.addAll(ActionProvider.ALL.stream()
.filter(p -> { .filter(p -> {
try { try {
if (!entry.getState().isUsable()) { if (!entry.getState().isUsable()) {
return false; return false;
} }
return p.getApplicableClass() var c = p.getDataSourceCallSite();
if (c == null) {
return false;
}
return c.getApplicableClass()
.isAssignableFrom(entry.getSource().getClass()) .isAssignableFrom(entry.getSource().getClass())
&& p.isApplicable(entry.getSource().asNeeded()); && c.isApplicable(entry.getSource().asNeeded());
} catch (Exception e) { } catch (Exception e) {
ErrorEvent.fromThrowable(e).handle(); ErrorEvent.fromThrowable(e).handle();
return false; return false;

View file

@ -45,9 +45,9 @@ public class SourceStorageEmptyIntroComp extends SimpleComp {
documentation.heightProperty().addListener((c, o, n) -> { documentation.heightProperty().addListener((c, o, n) -> {
dfi.iconSizeProperty().set(n.intValue()); dfi.iconSizeProperty().set(n.intValue());
}); });
var docLink = new Hyperlink(Hyperlinks.DOCS_GETTING_STARTED); var docLink = new Hyperlink(Hyperlinks.DOCUMENTATION);
docLink.setOnAction(e -> { docLink.setOnAction(e -> {
Hyperlinks.open(Hyperlinks.DOCS_GETTING_STARTED); Hyperlinks.open(Hyperlinks.DOCUMENTATION);
}); });
var docLinkPane = new StackPane(docLink); var docLinkPane = new StackPane(docLink);
docLinkPane.setAlignment(Pos.CENTER); docLinkPane.setAlignment(Pos.CENTER);

View file

@ -51,9 +51,9 @@ public class StoreStorageEmptyIntroComp extends SimpleComp {
documentation.heightProperty().addListener((c, o, n) -> { documentation.heightProperty().addListener((c, o, n) -> {
dofi.iconSizeProperty().set(n.intValue()); dofi.iconSizeProperty().set(n.intValue());
}); });
var docLink = new Hyperlink(Hyperlinks.DOCS_GETTING_STARTED); var docLink = new Hyperlink(Hyperlinks.DOCUMENTATION);
docLink.setOnAction(e -> { docLink.setOnAction(e -> {
Hyperlinks.open(Hyperlinks.DOCS_GETTING_STARTED); Hyperlinks.open(Hyperlinks.DOCUMENTATION);
}); });
var docLinkPane = new StackPane(docLink); var docLinkPane = new StackPane(docLink);
docLinkPane.setAlignment(Pos.CENTER); docLinkPane.setAlignment(Pos.CENTER);

View file

@ -1,6 +1,6 @@
package io.xpipe.app.core; package io.xpipe.app.core;
import io.xpipe.app.util.ConfigHelper; import io.xpipe.app.util.JsonConfigHelper;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
import io.xpipe.extension.Cache; import io.xpipe.extension.Cache;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;
@ -49,7 +49,7 @@ public class AppCache implements Cache {
var path = getPath(key); var path = getPath(key);
if (Files.exists(path)) { if (Files.exists(path)) {
try { try {
var tree = ConfigHelper.readConfig(path); var tree = JsonConfigHelper.readConfig(path);
if (tree.isMissingNode()) { if (tree.isMissingNode()) {
return notPresent.get(); return notPresent.get();
} }
@ -69,7 +69,7 @@ public class AppCache implements Cache {
try { try {
FileUtils.forceMkdirParent(path.toFile()); FileUtils.forceMkdirParent(path.toFile());
var tree = JacksonMapper.newMapper().valueToTree(val); var tree = JacksonMapper.newMapper().valueToTree(val);
ConfigHelper.writeConfig(path, tree); JsonConfigHelper.writeConfig(path, tree);
} catch (Exception e) { } catch (Exception e) {
ErrorEvent.fromThrowable("Could not parse cached data for key " + key, e) ErrorEvent.fromThrowable("Could not parse cached data for key " + key, e)
.omitted(true) .omitted(true)

View file

@ -4,11 +4,16 @@ import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.prefs.SupportedLocale; import io.xpipe.app.prefs.SupportedLocale;
import io.xpipe.app.util.ModuleHelper; import io.xpipe.app.util.ModuleHelper;
import io.xpipe.extension.I18n; import io.xpipe.extension.I18n;
import io.xpipe.extension.Translatable;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;
import io.xpipe.extension.event.TrackEvent; import io.xpipe.extension.event.TrackEvent;
import io.xpipe.extension.fxcomps.impl.FancyTooltipAugment;
import io.xpipe.extension.prefs.PrefsChoiceValue;
import io.xpipe.extension.util.DynamicOptionsBuilder;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding; import javafx.beans.binding.StringBinding;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import lombok.SneakyThrows;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.ocpsoft.prettytime.PrettyTime; import org.ocpsoft.prettytime.PrettyTime;
@ -89,11 +94,31 @@ public class AppI18n implements I18n {
prettyTime = null; prettyTime = null;
} }
@SneakyThrows
private static String getCallerModuleName() {
var callers = ModuleHelper.CallingClass.INSTANCE.getCallingClasses();
for (Class<?> caller : callers) {
if (caller.equals(ModuleHelper.CallingClass.class)
|| caller.equals(ModuleHelper.class)
|| caller.equals(AppI18n.class)
|| caller.equals(I18n.class)
|| caller.equals(FancyTooltipAugment.class)
|| caller.equals(PrefsChoiceValue.class)
|| caller.equals(Translatable.class)
|| caller.equals(DynamicOptionsBuilder.class)) {
continue;
}
var split = caller.getModule().getName().split("\\.");
return split[split.length - 1];
}
return "";
}
@Override @Override
public String getKey(String s) { public String getKey(String s) {
var key = s; var key = s;
if (!s.contains(".")) { if (!s.contains(".")) {
key = ModuleHelper.getCallerModuleName() + "." + s; key = getCallerModuleName() + "." + s;
} }
return key; return key;
} }

View file

@ -3,8 +3,8 @@ package io.xpipe.app.core.mode;
import io.xpipe.app.comp.storage.collection.SourceCollectionViewState; import io.xpipe.app.comp.storage.collection.SourceCollectionViewState;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.storage.store.StoreViewState;
import io.xpipe.app.core.*; import io.xpipe.app.core.*;
import io.xpipe.app.editor.EditorState; import io.xpipe.app.util.ExternalEditor;
import io.xpipe.app.grid.AppUpdater; import io.xpipe.app.update.AppUpdater;
import io.xpipe.app.issue.BasicErrorHandler; import io.xpipe.app.issue.BasicErrorHandler;
import io.xpipe.app.issue.ErrorHandler; import io.xpipe.app.issue.ErrorHandler;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
@ -40,7 +40,7 @@ public class BaseMode extends OperationMode {
AppCharsetter.init(); AppCharsetter.init();
DataStorage.init(); DataStorage.init();
FileWatchManager.init(); FileWatchManager.init();
EditorState.init(); ExternalEditor.init();
AppSocketServer.init(); AppSocketServer.init();
AppUpdater.init(); AppUpdater.init();
TrackEvent.info("mode", "Finished base components initialization"); TrackEvent.info("mode", "Finished base components initialization");

View file

@ -1,6 +1,6 @@
package io.xpipe.app.core.mode; package io.xpipe.app.core.mode;
import io.xpipe.app.grid.UpdateChangelogAlert; import io.xpipe.app.update.UpdateChangelogAlert;
import io.xpipe.app.core.App; import io.xpipe.app.core.App;
import io.xpipe.app.core.AppGreetings; import io.xpipe.app.core.AppGreetings;
import io.xpipe.app.issue.ErrorHandler; import io.xpipe.app.issue.ErrorHandler;

View file

@ -3,7 +3,7 @@ package io.xpipe.app.core.mode;
import io.xpipe.app.comp.storage.collection.SourceCollectionViewState; import io.xpipe.app.comp.storage.collection.SourceCollectionViewState;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.storage.store.StoreViewState;
import io.xpipe.app.core.*; import io.xpipe.app.core.*;
import io.xpipe.app.grid.UpdateAvailableAlert; import io.xpipe.app.update.UpdateAvailableAlert;
import io.xpipe.extension.event.TrackEvent; import io.xpipe.extension.event.TrackEvent;
import io.xpipe.extension.util.ThreadHelper; import io.xpipe.extension.util.ThreadHelper;
import javafx.application.Application; import javafx.application.Application;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.exchange.cli; package io.xpipe.app.exchange.cli;
import io.xpipe.app.exchange.MessageExchangeImpl; import io.xpipe.app.exchange.MessageExchangeImpl;
import io.xpipe.app.storage.XPipeInstanceHelper; import io.xpipe.app.update.XPipeInstanceHelper;
import io.xpipe.beacon.BeaconHandler; import io.xpipe.beacon.BeaconHandler;
import io.xpipe.beacon.exchange.cli.InstanceExchange; import io.xpipe.beacon.exchange.cli.InstanceExchange;
import io.xpipe.core.impl.LocalStore; import io.xpipe.core.impl.LocalStore;

View file

@ -3,7 +3,7 @@ package io.xpipe.app.issue;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.xpipe.app.core.*; import io.xpipe.app.core.*;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.grid.AppUpdater; import io.xpipe.app.update.AppUpdater;
import io.xpipe.extension.I18n; import io.xpipe.extension.I18n;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;
import javafx.application.Platform; import javafx.application.Platform;

View file

@ -16,6 +16,7 @@ import io.xpipe.extension.prefs.PrefsChoiceValue;
import io.xpipe.extension.prefs.PrefsHandler; import io.xpipe.extension.prefs.PrefsHandler;
import io.xpipe.extension.prefs.PrefsProvider; import io.xpipe.extension.prefs.PrefsProvider;
import io.xpipe.extension.util.XPipeDistributionType; import io.xpipe.extension.util.XPipeDistributionType;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
@ -26,6 +27,24 @@ import java.util.*;
public class AppPrefs { public class AppPrefs {
private static ObservableBooleanValue bindDeveloperTrue(ObservableBooleanValue o) {
return Bindings.createBooleanBinding(
() -> {
return AppPrefs.get().developerMode().getValue() || o.get();
},
o,
AppPrefs.get().developerMode());
}
private static ObservableBooleanValue bindDeveloperFalse(ObservableBooleanValue o) {
return Bindings.createBooleanBinding(
() -> {
return !AppPrefs.get().developerMode().getValue() || o.get();
},
o,
AppPrefs.get().developerMode());
}
private static final int tooltipDelayMin = 0; private static final int tooltipDelayMin = 0;
private static final int tooltipDelayMax = 1500; private static final int tooltipDelayMax = 1500;
private static final int fontSizeMin = 10; private static final int fontSizeMin = 10;
@ -134,7 +153,7 @@ public class AppPrefs {
private final ObjectProperty<Path> effectiveStorageDirectory = STORAGE_DIR_FIXED private final ObjectProperty<Path> effectiveStorageDirectory = STORAGE_DIR_FIXED
? new SimpleObjectProperty<>(AppProperties.get().getDataDir().resolve("storage")) ? new SimpleObjectProperty<>(AppProperties.get().getDataDir().resolve("storage"))
: internalStorageDirectory; : internalStorageDirectory;
private final StringField storageDirectoryControl = Fields.ofPath(effectiveStorageDirectory) private final StringField storageDirectoryControl = PrefFields.ofPath(effectiveStorageDirectory)
.editable(!STORAGE_DIR_FIXED) .editable(!STORAGE_DIR_FIXED)
.validate( .validate(
CustomValidators.absolutePath(), CustomValidators.absolutePath(),
@ -230,24 +249,24 @@ public class AppPrefs {
return effectiveDeveloperMode; return effectiveDeveloperMode;
} }
public ReadOnlyBooleanProperty developerDisableUpdateVersionCheck() { public ObservableBooleanValue developerDisableUpdateVersionCheck() {
return developerDisableUpdateVersionCheck; return bindDeveloperTrue(developerDisableUpdateVersionCheck);
} }
public ReadOnlyBooleanProperty developerDisableGuiRestrictions() { public ObservableBooleanValue developerDisableGuiRestrictions() {
return developerDisableGuiRestrictions; return bindDeveloperTrue(developerDisableGuiRestrictions);
} }
public ReadOnlyBooleanProperty developerDisableConnectorInstallationVersionCheck() { public ObservableBooleanValue developerDisableConnectorInstallationVersionCheck() {
return developerDisableConnectorInstallationVersionCheck; return bindDeveloperTrue(developerDisableConnectorInstallationVersionCheck);
} }
public ReadOnlyBooleanProperty developerShowHiddenProviders() { public ObservableBooleanValue developerShowHiddenProviders() {
return developerShowHiddenProviders; return bindDeveloperTrue(developerShowHiddenProviders);
} }
public ReadOnlyBooleanProperty developerShowHiddenEntries() { public ObservableBooleanValue developerShowHiddenEntries() {
return developerShowHiddenEntries; return bindDeveloperTrue(developerShowHiddenEntries);
} }
private AppPreferencesFx preferencesFx; private AppPreferencesFx preferencesFx;

View file

@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode; import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.databind.type.CollectionType;
import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppProperties;
import io.xpipe.app.util.ConfigHelper; import io.xpipe.app.util.JsonConfigHelper;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;
import io.xpipe.extension.event.TrackEvent; import io.xpipe.extension.event.TrackEvent;
@ -32,7 +32,7 @@ public class JsonStorageHandler implements StorageHandler {
private JsonNode getContent(String key) { private JsonNode getContent(String key) {
if (content == null) { if (content == null) {
content = (ObjectNode) ConfigHelper.readConfig(file); content = (ObjectNode) JsonConfigHelper.readConfig(file);
} }
return content.get(key); return content.get(key);
} }
@ -42,7 +42,7 @@ public class JsonStorageHandler implements StorageHandler {
} }
void save() { void save() {
ConfigHelper.writeConfig(file, content); JsonConfigHelper.writeConfig(file, content);
} }
@Override @Override

View file

@ -11,7 +11,7 @@ import javafx.util.StringConverter;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
public class Fields { public class PrefFields {
public static StringField ofPath(ObjectProperty<Path> fileProperty) { public static StringField ofPath(ObjectProperty<Path> fileProperty) {
StringProperty stringProperty = new SimpleStringProperty(); StringProperty stringProperty = new SimpleStringProperty();

View file

@ -1,6 +0,0 @@
package io.xpipe.app.storage;
public enum AccessMode {
READ,
WRITE
}

View file

@ -1,6 +0,0 @@
package io.xpipe.app.storage;
import java.time.Instant;
import java.util.UUID;
public record ApplicationAccess(String name, UUID uuid, Instant start, AccessMode mode) {}

View file

@ -1,4 +1,4 @@
package io.xpipe.app.grid; package io.xpipe.app.update;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;

View file

@ -1,10 +1,10 @@
package io.xpipe.app.grid; package io.xpipe.app.update;
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.app.util.TerminalProvider;
import io.xpipe.core.impl.FileNames; import io.xpipe.core.impl.FileNames;
import io.xpipe.core.impl.LocalProcessControlProvider;
import io.xpipe.core.process.CommandProcessControl; import io.xpipe.core.process.CommandProcessControl;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellProcessControl; import io.xpipe.core.process.ShellProcessControl;
@ -196,8 +196,7 @@ public class AppInstaller {
var command = "set -x\n" + "DEBIAN_FRONTEND=noninteractive sudo apt-get remove -qy xpipe\n" var command = "set -x\n" + "DEBIAN_FRONTEND=noninteractive sudo apt-get remove -qy xpipe\n"
+ "DEBIAN_FRONTEND=noninteractive sudo apt-get install -qy \"" + file + "\"\n" + "DEBIAN_FRONTEND=noninteractive sudo apt-get install -qy \"" + file + "\"\n"
+ "xpipe daemon start"; + "xpipe daemon start";
var script = ScriptHelper.createLocalExecScript(command); TerminalProvider.open("X-Pipe Updater", command);
LocalProcessControlProvider.get().openInTerminal("X-Pipe Updater", script);
} }
} }
@ -223,8 +222,7 @@ public class AppInstaller {
@Override @Override
public void installLocal(String file) throws Exception { public void installLocal(String file) throws Exception {
var command = "set -x\n" + "sudo rpm -U -v --force \"" + file + "\"\n" + "xpipe daemon start"; var command = "set -x\n" + "sudo rpm -U -v --force \"" + file + "\"\n" + "xpipe daemon start";
var script = ScriptHelper.createLocalExecScript(command); TerminalProvider.open("X-Pipe Updater", command);
LocalProcessControlProvider.get().openInTerminal("X-Pipe Updater", script);
} }
} }
@ -250,8 +248,7 @@ public class AppInstaller {
@Override @Override
public void installLocal(String file) throws Exception { public void installLocal(String file) throws Exception {
var command = "set -x\n" + "sudo installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /\n" + "xpipe daemon start"; var command = "set -x\n" + "sudo installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /\n" + "xpipe daemon start";
var script = ScriptHelper.createLocalExecScript(command); TerminalProvider.open("X-Pipe Updater", command);
LocalProcessControlProvider.get().openInTerminal("X-Pipe Updater", script);
} }
} }
} }

View file

@ -1,4 +1,4 @@
package io.xpipe.app.grid; package io.xpipe.app.update;
import io.xpipe.app.core.AppCache; import io.xpipe.app.core.AppCache;
import io.xpipe.extension.util.XPipeDistributionType; import io.xpipe.extension.util.XPipeDistributionType;
@ -6,7 +6,7 @@ import io.xpipe.app.core.AppExtensionManager;
import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.impl.LocalProcessControlProvider; import io.xpipe.core.impl.ProcessControlProvider;
import io.xpipe.core.util.XPipeSession; import io.xpipe.core.util.XPipeSession;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;
import io.xpipe.extension.event.TrackEvent; import io.xpipe.extension.event.TrackEvent;
@ -112,7 +112,7 @@ public class AppUpdater {
if (layer == null) { if (layer == null) {
return; return;
} }
LocalProcessControlProvider.init(layer); ProcessControlProvider.init(layer);
INSTANCE = new AppUpdater(); INSTANCE = new AppUpdater();
} }

View file

@ -1,4 +1,4 @@
package io.xpipe.app.grid; package io.xpipe.app.update;
import io.xpipe.app.core.AppWindowHelper; import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.extension.I18n; import io.xpipe.extension.I18n;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.grid; package io.xpipe.app.update;
import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.AppWindowHelper; import io.xpipe.app.core.AppWindowHelper;

View file

@ -1,6 +1,7 @@
package io.xpipe.app.storage; package io.xpipe.app.update;
import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppProperties;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.beacon.XPipeInstance; import io.xpipe.beacon.XPipeInstance;
import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.ShellStore;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;

View file

@ -1,29 +0,0 @@
package io.xpipe.app.util;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.core.util.SecretValue;
import io.xpipe.extension.I18n;
import javafx.scene.control.Alert;
import javafx.scene.control.PasswordField;
import java.util.concurrent.atomic.AtomicReference;
public class AskpassAlert {
public static SecretValue query() {
AtomicReference<SecretValue> password = new AtomicReference<>();
var result = AppWindowHelper.showBlockingAlert(alert -> {
alert.setAlertType(Alert.AlertType.CONFIRMATION);
alert.setTitle(I18n.get("providePassword"));
alert.setHeaderText(I18n.get("queryPasswordDescription"));
var textField = new PasswordField();
textField.textProperty().addListener((c, o, n) -> {
password.set(new SecretValue(n));
});
alert.getDialogPane().setContent(textField);
})
.filter(buttonType -> buttonType.getButtonData().isDefaultButton());
return result.isPresent() ? password.get() : null;
}
}

View file

@ -1,26 +0,0 @@
package io.xpipe.app.util;
import io.xpipe.app.prefs.AppPrefs;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableBooleanValue;
public class DeveloperHelper {
public static ObservableBooleanValue bindTrue(ObservableBooleanValue o) {
return Bindings.createBooleanBinding(
() -> {
return AppPrefs.get().developerMode().getValue() || o.get();
},
o,
AppPrefs.get().developerMode());
}
public static ObservableBooleanValue bindFalls(ObservableBooleanValue o) {
return Bindings.createBooleanBinding(
() -> {
return !AppPrefs.get().developerMode().getValue() || o.get();
},
o,
AppPrefs.get().developerMode());
}
}

View file

@ -1,4 +1,4 @@
package io.xpipe.app.editor; package io.xpipe.app.util;
import io.xpipe.app.core.FileWatchManager; import io.xpipe.app.core.FileWatchManager;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
@ -22,14 +22,14 @@ import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer; import java.util.function.Consumer;
public class EditorState { public class ExternalEditor {
private static final Path TEMP = private static final Path TEMP =
FileUtils.getTempDirectory().toPath().resolve("xpipe").resolve("editor"); FileUtils.getTempDirectory().toPath().resolve("xpipe").resolve("editor");
private static EditorState INSTANCE; private static ExternalEditor INSTANCE;
private final Set<Entry> openEntries = new CopyOnWriteArraySet<>(); private final Set<Entry> openEntries = new CopyOnWriteArraySet<>();
public static EditorState get() { public static ExternalEditor get() {
return INSTANCE; return INSTANCE;
} }
@ -42,7 +42,7 @@ public class EditorState {
} }
public static void init() { public static void init() {
INSTANCE = new EditorState(); INSTANCE = new ExternalEditor();
try { try {
FileUtils.forceMkdir(TEMP.toFile()); FileUtils.forceMkdir(TEMP.toFile());

View file

@ -1,66 +0,0 @@
package io.xpipe.app.util;
import com.vladsch.flexmark.util.sequence.Html5Entities;
import io.xpipe.modulefs.ModuleFileSystem;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
public class FlexmarkHelper {
public static void loadHtmlEscapes() {
Class<?> c = null;
try {
c = Html5Entities.class;
Html5Entities.entityToString(null);
} catch (Throwable ignored) {
}
try {
var field = c.getDeclaredField("NAMED_CHARACTER_REFERENCES");
field.setAccessible(true);
field.setInt(field, field.getModifiers() & ~Modifier.FINAL);
try (var fs = ModuleFileSystem.create("module:/com.vladsch.flexmark_util_html")) {
var file = fs.getPath("com/vladsch/flexmark/util/html/entities.properties");
try (var in = Files.newInputStream(file)) {
var r = readEntities(in);
field.set(null, r);
}
}
} catch (Exception ignored) {
ignored.printStackTrace();
}
}
private static Map<String, String> readEntities(InputStream stream) {
Map<String, String> entities = new HashMap<>();
Charset charset = StandardCharsets.UTF_8;
try {
String line;
InputStreamReader streamReader = new InputStreamReader(stream, charset);
BufferedReader bufferedReader = new BufferedReader(streamReader);
while ((line = bufferedReader.readLine()) != null) {
if (line.length() == 0) {
continue;
}
int equal = line.indexOf("=");
String key = line.substring(0, equal);
String value = line.substring(equal + 1);
entities.put(key, value);
}
} catch (IOException e) {
throw new IllegalStateException("Failed reading data for HTML named character references", e);
}
entities.put("NewLine", "\n");
return entities;
}
}

View file

@ -9,17 +9,12 @@ import java.net.URI;
public class Hyperlinks { public class Hyperlinks {
public static final String WEBSITE = "https://xpipe.io"; public static final String WEBSITE = "https://xpipe.io";
public static final String DOCUMENTATION = "https://docs.xpipe.io"; public static final String DOCUMENTATION = "https://xpipe.io/docs";
public static final String GITHUB = "https://github.com/xpipe-io"; public static final String GITHUB = "https://github.com/xpipe-io";
public static final String DISCORD = "https://discord.gg/8y89vS8cRb"; public static final String DISCORD = "https://discord.gg/8y89vS8cRb";
public static final String SLACK = public static final String SLACK =
"https://join.slack.com/t/x-pipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg"; "https://join.slack.com/t/x-pipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg";
public static final String DOCS_PRIVACY = "https://xpipe.io/docs/privacy";
public static final String GUIDE = "https://github.com/crschnick/pdx_unlimiter/wiki/User-Guide";
public static final String DOCS_DATA_INPUT = "https://docs.xpipe.io/data-source-creation/data-input";
public static final String DOCS_BASE = "https://docs.xpipe.io/";
public static final String DOCS_GETTING_STARTED = "https://docs.xpipe.io/en/latest/index.html";
public static final String DOCS_PRIVACY = "https://docs.xpipe.io/en/latest/privacy.html";
public static Runnable openLink(String s) { public static Runnable openLink(String s) {
return () -> open(s); return () -> open(s);

View file

@ -15,13 +15,13 @@ import java.io.StringWriter;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
public class ConfigHelper { public class JsonConfigHelper {
public static JsonNode readConfig(Path in) { public static JsonNode readConfig(Path in) {
JsonNode node = JsonNodeFactory.instance.objectNode(); JsonNode node = JsonNodeFactory.instance.objectNode();
try { try {
if (Files.exists(in)) { if (Files.exists(in)) {
ObjectMapper o = JacksonMapper.newMapper(); ObjectMapper o = JacksonMapper.getDefault();
node = o.readTree(Files.readAllBytes(in)); node = o.readTree(Files.readAllBytes(in));
} }
} catch (IOException e) { } catch (IOException e) {
@ -41,7 +41,7 @@ public class ConfigHelper {
var writer = new StringWriter(); var writer = new StringWriter();
JsonFactory f = new JsonFactory(); JsonFactory f = new JsonFactory();
try (JsonGenerator g = f.createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter())) { try (JsonGenerator g = f.createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter())) {
JacksonMapper.newMapper().writeTree(g, node); JacksonMapper.getDefault().writeTree(g, node);
var newContent = writer.toString(); var newContent = writer.toString();
Files.writeString(out, newContent); Files.writeString(out, newContent);
} catch (IOException e) { } catch (IOException e) {

View file

@ -1,11 +1,5 @@
package io.xpipe.app.util; package io.xpipe.app.util;
import io.xpipe.app.core.AppI18n;
import io.xpipe.extension.I18n;
import io.xpipe.extension.Translatable;
import io.xpipe.extension.fxcomps.impl.FancyTooltipAugment;
import io.xpipe.extension.prefs.PrefsChoiceValue;
import io.xpipe.extension.util.DynamicOptionsBuilder;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -13,26 +7,6 @@ import java.lang.reflect.Method;
public class ModuleHelper { public class ModuleHelper {
@SneakyThrows
public static String getCallerModuleName() {
var callers = CallingClass.INSTANCE.getCallingClasses();
for (Class<?> caller : callers) {
if (caller.equals(CallingClass.class)
|| caller.equals(ModuleHelper.class)
|| caller.equals(AppI18n.class)
|| caller.equals(I18n.class)
|| caller.equals(FancyTooltipAugment.class)
|| caller.equals(PrefsChoiceValue.class)
|| caller.equals(Translatable.class)
|| caller.equals(DynamicOptionsBuilder.class)) {
continue;
}
var split = caller.getModule().getName().split("\\.");
return split[split.length - 1];
}
return "";
}
public static boolean isImage() { public static boolean isImage() {
return ModuleHelper.class return ModuleHelper.class
.getProtectionDomain() .getProtectionDomain()

View file

@ -2,8 +2,8 @@ package io.xpipe.app.util;
import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppWindowHelper; import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.grid.AppDownloads; import io.xpipe.app.update.AppDownloads;
import io.xpipe.app.grid.AppInstaller; import io.xpipe.app.update.AppInstaller;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.impl.FileNames; import io.xpipe.core.impl.FileNames;
import io.xpipe.core.process.ShellProcessControl; import io.xpipe.core.process.ShellProcessControl;

View file

@ -0,0 +1,39 @@
package io.xpipe.app.util;
import io.xpipe.extension.util.ModuleLayerLoader;
import io.xpipe.extension.util.ScriptHelper;
import java.util.ServiceLoader;
public abstract class TerminalProvider {
private static TerminalProvider INSTANCE;
public static class Loader implements ModuleLayerLoader {
@Override
public void init(ModuleLayer layer) {
ServiceLoader.load(layer, TerminalProvider.class).findFirst().orElseThrow();
}
@Override
public boolean requiresFullDaemon() {
return true;
}
@Override
public boolean prioritizeLoading() {
return false;
}
}
public static void open(String title, String command) throws Exception {
if (command.contains("\n")) {
command = ScriptHelper.createLocalExecScript(command);
}
INSTANCE.openInTerminal(title, command);
}
protected abstract void openInTerminal(String title, String command) throws Exception;
}

View file

@ -7,7 +7,7 @@ import io.xpipe.app.comp.source.store.NamedStoreChoiceComp;
import io.xpipe.app.core.AppImages; import io.xpipe.app.core.AppImages;
import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppResources; import io.xpipe.app.core.AppResources;
import io.xpipe.app.grid.AppDownloads; import io.xpipe.app.update.AppDownloads;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.core.charsetter.Charsetter; import io.xpipe.core.charsetter.Charsetter;

View file

@ -27,8 +27,7 @@ open module io.xpipe.app {
exports io.xpipe.app.prefs; exports io.xpipe.app.prefs;
exports io.xpipe.app.comp.source.store; exports io.xpipe.app.comp.source.store;
exports io.xpipe.app.storage; exports io.xpipe.app.storage;
exports io.xpipe.app.editor; exports io.xpipe.app.update;
exports io.xpipe.app.grid;
exports io.xpipe.app.comp.storage; exports io.xpipe.app.comp.storage;
exports io.xpipe.app.comp.storage.collection; exports io.xpipe.app.comp.storage.collection;
@ -98,6 +97,7 @@ open module io.xpipe.app {
requires jdk.jdwp.agent; requires jdk.jdwp.agent;
uses MessageExchangeImpl; uses MessageExchangeImpl;
uses io.xpipe.app.util.TerminalProvider;
provides DataStateProvider with provides DataStateProvider with
DataStateProviderImpl; DataStateProviderImpl;

View file

@ -3,7 +3,6 @@ package io.xpipe.cli;
import io.xpipe.beacon.exchange.MessageExchanges; import io.xpipe.beacon.exchange.MessageExchanges;
import io.xpipe.cli.util.CliProperties; import io.xpipe.cli.util.CliProperties;
import io.xpipe.cli.util.PrettyTimeHelper; import io.xpipe.cli.util.PrettyTimeHelper;
import io.xpipe.core.impl.LocalProcessControlProvider;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
public class BuildTimeInitialization { public class BuildTimeInitialization {
@ -13,7 +12,6 @@ public class BuildTimeInitialization {
CliProperties.init(); CliProperties.init();
JacksonMapper.initClassBased(); JacksonMapper.initClassBased();
MessageExchanges.loadAll(); MessageExchanges.loadAll();
LocalProcessControlProvider.init(null);
PrettyTimeHelper.init(); PrettyTimeHelper.init();
// System.out.println("Ending build time initialization"); // System.out.println("Ending build time initialization");
} }

View file

@ -1,6 +1,6 @@
package io.xpipe.cli.test; package io.xpipe.cli.test;
import io.xpipe.extension.util.DaemonExtensionTest; import io.xpipe.extension.test.DaemonExtensionTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.IOException; import java.io.IOException;

View file

@ -1,6 +1,6 @@
package io.xpipe.cli.test; package io.xpipe.cli.test;
import io.xpipe.extension.util.DaemonExtensionTest; import io.xpipe.extension.test.DaemonExtensionTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;

View file

@ -1,6 +1,6 @@
package io.xpipe.cli.test; package io.xpipe.cli.test;
import io.xpipe.extension.util.DaemonExtensionTest; import io.xpipe.extension.test.DaemonExtensionTest;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;

View file

@ -1,6 +1,6 @@
package io.xpipe.cli.test; package io.xpipe.cli.test;
import io.xpipe.extension.util.ExtensionTest; import io.xpipe.extension.test.ExtensionTest;
import lombok.Getter; import lombok.Getter;
import java.nio.file.Path; import java.nio.file.Path;

View file

@ -1,40 +0,0 @@
package io.xpipe.core.impl;
import io.xpipe.core.process.ShellProcessControl;
import java.util.ServiceLoader;
public abstract class LocalProcessControlProvider {
private static LocalProcessControlProvider INSTANCE;
public static LocalProcessControlProvider get() {
if (INSTANCE == null) {
throw new IllegalStateException("Process control not initialized");
}
return INSTANCE;
}
public static void init(ModuleLayer layer) {
INSTANCE = layer != null
? ServiceLoader.load(layer, LocalProcessControlProvider.class)
.findFirst()
.orElse(null)
: ServiceLoader.load(LocalProcessControlProvider.class)
.findFirst()
.orElse(null);
}
public static ShellProcessControl create() {
if (INSTANCE == null) {
throw new IllegalStateException("Not initialized");
}
return INSTANCE.createProcessControl();
}
public abstract ShellProcessControl createProcessControl();
public abstract void openInTerminal(String title, String command) throws Exception;
}

View file

@ -48,7 +48,7 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
@Override @Override
public ShellProcessControl create() { public ShellProcessControl create() {
return LocalProcessControlProvider.create(); return ProcessControlProvider.createLocal();
} }
} }

View file

@ -0,0 +1,50 @@
package io.xpipe.core.impl;
import io.xpipe.core.process.CommandProcessControl;
import io.xpipe.core.process.ShellProcessControl;
import lombok.NonNull;
import java.util.List;
import java.util.ServiceLoader;
import java.util.function.BiFunction;
import java.util.function.Function;
public abstract class ProcessControlProvider {
private static List<ProcessControlProvider> INSTANCES;
public static void init(ModuleLayer layer) {
INSTANCES = ServiceLoader.load(layer, ProcessControlProvider.class)
.stream().map(localProcessControlProviderProvider -> localProcessControlProviderProvider.get()).toList();
}
public static ShellProcessControl createLocal() {
return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.createLocalProcessControl()).findFirst().orElseThrow();
}
public static ShellProcessControl createSub(
ShellProcessControl parent,
@NonNull Function<ShellProcessControl, String> commandFunction,
BiFunction<ShellProcessControl, String, String> terminalCommand) {
return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.sub(parent, commandFunction, terminalCommand)).findFirst().orElseThrow();
}
public static CommandProcessControl createCommand(
ShellProcessControl parent,
@NonNull Function<ShellProcessControl, String> command,
Function<ShellProcessControl, String> terminalCommand) {
return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.command(parent, command, terminalCommand)).findFirst().orElseThrow();
}
public abstract ShellProcessControl sub(
ShellProcessControl parent,
@NonNull Function<ShellProcessControl, String> commandFunction,
BiFunction<ShellProcessControl, String, String> terminalCommand);
public abstract CommandProcessControl command(
ShellProcessControl parent,
@NonNull Function<ShellProcessControl, String> command,
Function<ShellProcessControl, String> terminalCommand);
public abstract ShellProcessControl createLocalProcessControl();
}

View file

@ -1,4 +1,4 @@
import io.xpipe.core.impl.LocalProcessControlProvider; import io.xpipe.core.impl.ProcessControlProvider;
import io.xpipe.core.source.WriteMode; import io.xpipe.core.source.WriteMode;
import io.xpipe.core.util.CoreJacksonModule; import io.xpipe.core.util.CoreJacksonModule;
@ -24,7 +24,7 @@ open module io.xpipe.core {
uses com.fasterxml.jackson.databind.Module; uses com.fasterxml.jackson.databind.Module;
uses io.xpipe.core.source.WriteMode; uses io.xpipe.core.source.WriteMode;
uses LocalProcessControlProvider; uses ProcessControlProvider;
uses io.xpipe.core.util.ProxyProvider; uses io.xpipe.core.util.ProxyProvider;
uses io.xpipe.core.util.ProxyManagerProvider; uses io.xpipe.core.util.ProxyManagerProvider;
uses io.xpipe.core.util.DataStateProvider; uses io.xpipe.core.util.DataStateProvider;

View file

@ -1,6 +1,6 @@
package io.xpipe.ext.base.actions; package io.xpipe.ext.base.actions;
import io.xpipe.app.editor.EditorState; import io.xpipe.app.util.ExternalEditor;
import io.xpipe.core.impl.FileStore; import io.xpipe.core.impl.FileStore;
import io.xpipe.core.impl.LocalStore; import io.xpipe.core.impl.LocalStore;
import io.xpipe.core.store.DataFlow; import io.xpipe.core.store.DataFlow;
@ -33,9 +33,9 @@ public class FileEditAction implements DataStoreActionProvider<FileStore> {
@Override @Override
public void execute(FileStore store) throws Exception { public void execute(FileStore store) throws Exception {
if (store.getFileSystem().equals(new LocalStore())) { if (store.getFileSystem().equals(new LocalStore())) {
EditorState.get().openInEditor(store.getFile()); ExternalEditor.get().openInEditor(store.getFile());
} else { } else {
EditorState.get() ExternalEditor.get()
.startEditing(store.getFileName(), store.getFileExtension(), store, () -> store.openInput(), () -> store.openOutput()); .startEditing(store.getFileName(), store.getFileExtension(), store, () -> store.openInput(), () -> store.openOutput());
} }
} }

View file

@ -57,7 +57,7 @@ public class CommandLineTarget implements DataSourceTarget {
@Override @Override
public String getSetupGuideURL() { public String getSetupGuideURL() {
return "https://docs.xpipe.io/en/latest/guide/cli/index.html"; return "https://xpipe.io/docs/en/latest/guide/cli/index.html";
} }
@Override @Override

View file

@ -118,6 +118,6 @@ public class JavaTarget implements DataSourceTarget {
@Override @Override
public String getSetupGuideURL() { public String getSetupGuideURL() {
return "https://docs.xpipe.io/en/latest/api/java.html"; return "https://xpipe.io/docs/en/latest/api/java.html";
} }
} }

View file

@ -5,7 +5,7 @@ import io.xpipe.core.charsetter.NewLine;
import io.xpipe.core.charsetter.StreamCharset; import io.xpipe.core.charsetter.StreamCharset;
import io.xpipe.core.impl.FileStore; import io.xpipe.core.impl.FileStore;
import io.xpipe.core.impl.TextSource; import io.xpipe.core.impl.TextSource;
import io.xpipe.extension.util.DaemonExtensionTest; import io.xpipe.extension.test.DaemonExtensionTest;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View file

@ -5,7 +5,7 @@ import io.xpipe.core.data.node.ValueNode;
import io.xpipe.ext.csv.CsvDelimiter; import io.xpipe.ext.csv.CsvDelimiter;
import io.xpipe.ext.csv.CsvHeaderState; import io.xpipe.ext.csv.CsvHeaderState;
import io.xpipe.ext.csv.CsvSource; import io.xpipe.ext.csv.CsvSource;
import io.xpipe.extension.util.DaemonExtensionTest; import io.xpipe.extension.test.DaemonExtensionTest;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View file

@ -1,51 +0,0 @@
package io.xpipe.extension;
import io.xpipe.core.source.DataSource;
import io.xpipe.extension.event.ErrorEvent;
import javafx.beans.value.ObservableValue;
import javafx.scene.layout.Region;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
public interface DataSourceActionProvider<T extends DataSource<?>> {
static List<DataSourceActionProvider<?>> ALL = new ArrayList<>();
public static void init(ModuleLayer layer) {
if (ALL.size() == 0) {
ALL.addAll(ServiceLoader.load(layer, DataSourceActionProvider.class).stream()
.map(p -> (DataSourceActionProvider<?>) p.get())
.filter(provider -> {
try {
return provider.isActive();
} catch (Throwable e) {
ErrorEvent.fromThrowable(e).handle();
return false;
}
})
.toList());
}
}
Class<T> getApplicableClass();
default boolean isActive() throws Exception {
return true;
}
default boolean isApplicable(T o) throws Exception {
return true;
}
default void applyToRegion(T store, Region region) {
}
ObservableValue<String> getName(T store);
String getIcon(T store);
default void execute(T store) throws Exception {
}
}

View file

@ -31,6 +31,11 @@ public interface DataSourceTarget {
public boolean requiresFullDaemon() { public boolean requiresFullDaemon() {
return true; return true;
} }
@Override
public boolean prioritizeLoading() {
return false;
}
} }
public static Optional<DataSourceTarget> byId(String id) { public static Optional<DataSourceTarget> byId(String id) {

View file

@ -1,19 +1,19 @@
package io.xpipe.extension; package io.xpipe.extension;
import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.jsontype.NamedType;
import io.xpipe.core.impl.LocalProcessControlProvider; import io.xpipe.core.impl.ProcessControlProvider;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
import io.xpipe.core.util.ProxyFunction; import io.xpipe.core.util.ProxyFunction;
import io.xpipe.extension.event.TrackEvent; import io.xpipe.extension.event.TrackEvent;
import io.xpipe.extension.prefs.PrefsProvider;
import io.xpipe.extension.util.ActionProvider;
import io.xpipe.extension.util.ModuleLayerLoader; import io.xpipe.extension.util.ModuleLayerLoader;
import io.xpipe.extension.util.XPipeDaemon; import io.xpipe.extension.util.XPipeDaemon;
public class XPipeServiceProviders { public class XPipeServiceProviders {
public static void load(ModuleLayer layer) { public static void load(ModuleLayer layer) {
LocalProcessControlProvider.init(layer); var hasDaemon = XPipeDaemon.getInstanceIfPresent().isPresent();
ModuleLayerLoader.loadAll(layer, hasDaemon, true);
ProcessControlProvider.init(layer);
TrackEvent.info("Loading extension providers ..."); TrackEvent.info("Loading extension providers ...");
DataSourceProviders.init(layer); DataSourceProviders.init(layer);
@ -34,14 +34,10 @@ public class XPipeServiceProviders {
}); });
} }
var hasDaemon = XPipeDaemon.getInstanceIfPresent().isPresent(); ModuleLayerLoader.loadAll(layer, hasDaemon, false);
ModuleLayerLoader.loadAll(layer, hasDaemon);
if (hasDaemon) { if (hasDaemon) {
ActionProvider.init(layer);
DataSourceActionProvider.init(layer);
ProxyFunction.init(layer); ProxyFunction.init(layer);
PrefsProvider.init(layer);
} }
TrackEvent.info("Finished loading extension providers"); TrackEvent.info("Finished loading extension providers");

View file

@ -1,6 +1,7 @@
package io.xpipe.extension.prefs; package io.xpipe.extension.prefs;
import com.dlsc.formsfx.model.structure.Field; import com.dlsc.formsfx.model.structure.Field;
import io.xpipe.extension.util.ModuleLayerLoader;
import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableBooleanValue;
import java.util.ServiceLoader; import java.util.ServiceLoader;
@ -11,12 +12,24 @@ public abstract class PrefsProvider {
private static Set<PrefsProvider> ALL; private static Set<PrefsProvider> ALL;
public static void init(ModuleLayer layer) { public static class Loader implements ModuleLayerLoader {
if (ALL == null) {
@Override
public void init(ModuleLayer layer) {
ALL = ServiceLoader.load(layer, PrefsProvider.class).stream() ALL = ServiceLoader.load(layer, PrefsProvider.class).stream()
.map(ServiceLoader.Provider::get) .map(ServiceLoader.Provider::get)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@Override
public boolean requiresFullDaemon() {
return true;
}
@Override
public boolean prioritizeLoading() {
return false;
}
} }
public static Set<PrefsProvider> getAll() { public static Set<PrefsProvider> getAll() {

View file

@ -1,4 +1,4 @@
package io.xpipe.extension.util; package io.xpipe.extension.test;
import io.xpipe.api.DataSource; import io.xpipe.api.DataSource;
import io.xpipe.beacon.BeaconDaemonController; import io.xpipe.beacon.BeaconDaemonController;

View file

@ -1,4 +1,4 @@
package io.xpipe.extension.util; package io.xpipe.extension.test;
import io.xpipe.core.data.node.DataStructureNode; import io.xpipe.core.data.node.DataStructureNode;
import io.xpipe.core.impl.FileStore; import io.xpipe.core.impl.FileStore;

View file

@ -1,4 +1,4 @@
package io.xpipe.extension.util; package io.xpipe.extension.test;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
import io.xpipe.core.util.XPipeSession; import io.xpipe.core.util.XPipeSession;

View file

@ -1,5 +1,6 @@
package io.xpipe.extension.util; package io.xpipe.extension.util;
import io.xpipe.core.source.DataSource;
import io.xpipe.core.store.DataStore; import io.xpipe.core.store.DataStore;
import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.event.ErrorEvent;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
@ -7,15 +8,18 @@ import javafx.beans.value.ObservableValue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.stream.Collectors;
public interface ActionProvider { public interface ActionProvider {
static List<ActionProvider> ALL = new ArrayList<>(); static List<ActionProvider> ALL = new ArrayList<>();
public static void init(ModuleLayer layer) { public static class Loader implements ModuleLayerLoader {
if (ALL.size() == 0) {
@Override
public void init(ModuleLayer layer) {
ALL.addAll(ServiceLoader.load(layer, ActionProvider.class).stream() ALL.addAll(ServiceLoader.load(layer, ActionProvider.class).stream()
.map(p -> (ActionProvider) p.get()) .map(actionProviderProvider -> actionProviderProvider.get())
.filter(provider -> { .filter(provider -> {
try { try {
return provider.isActive(); return provider.isActive();
@ -24,7 +28,17 @@ public interface ActionProvider {
return false; return false;
} }
}) })
.toList()); .collect(Collectors.toSet()));
}
@Override
public boolean requiresFullDaemon() {
return true;
}
@Override
public boolean prioritizeLoading() {
return false;
} }
} }
@ -39,7 +53,6 @@ public interface ActionProvider {
return true; return true;
} }
interface LauncherCallSite { interface LauncherCallSite {
String getId(); String getId();
@ -55,6 +68,11 @@ public interface ActionProvider {
return null; return null;
} }
default DataSourceCallSite<?> getDataSourceCallSite() {
return null;
}
public static interface DataStoreCallSite<T extends DataStore> { public static interface DataStoreCallSite<T extends DataStore> {
Action createAction(T store); Action createAction(T store);
@ -64,6 +82,7 @@ public interface ActionProvider {
default boolean isMajor() { default boolean isMajor() {
return false; return false;
} }
default boolean isApplicable(T o) throws Exception { default boolean isApplicable(T o) throws Exception {
return true; return true;
} }
@ -76,4 +95,27 @@ public interface ActionProvider {
return true; return true;
} }
} }
public static interface DataSourceCallSite<T extends DataSource<?>> {
Action createAction(T source);
Class<T> getApplicableClass();
default boolean isMajor() {
return false;
}
default boolean isApplicable(T o) throws Exception {
return true;
}
ObservableValue<String> getName(T source);
String getIcon(T source);
default boolean showIfDisabled() {
return true;
}
}
} }

View file

@ -6,13 +6,18 @@ import java.util.ServiceLoader;
public interface ModuleLayerLoader { public interface ModuleLayerLoader {
public static void loadAll(ModuleLayer layer, boolean hasDaemon) { public static void loadAll(ModuleLayer layer, boolean hasDaemon, boolean prioritization) {
ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> { ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> {
var instance = moduleLayerLoaderProvider.get(); var instance = moduleLayerLoaderProvider.get();
try { try {
if (instance.requiresFullDaemon() && !hasDaemon) { if (instance.requiresFullDaemon() && !hasDaemon) {
return; return;
} }
if (instance.prioritizeLoading() != prioritization) {
return;
}
instance.init(layer); instance.init(layer);
} catch (Throwable t) { } catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle(); ErrorEvent.fromThrowable(t).handle();
@ -23,4 +28,6 @@ public interface ModuleLayerLoader {
public void init(ModuleLayer layer); public void init(ModuleLayer layer);
boolean requiresFullDaemon(); boolean requiresFullDaemon();
boolean prioritizeLoading();
} }

View file

@ -2,6 +2,7 @@ import io.xpipe.core.util.ProxyFunction;
import io.xpipe.extension.DataSourceProvider; import io.xpipe.extension.DataSourceProvider;
import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.DataStoreActionProvider;
import io.xpipe.extension.DataSourceTarget; import io.xpipe.extension.DataSourceTarget;
import io.xpipe.extension.prefs.PrefsProvider;
import io.xpipe.extension.util.ActionProvider; import io.xpipe.extension.util.ActionProvider;
import io.xpipe.extension.util.ModuleLayerLoader; import io.xpipe.extension.util.ModuleLayerLoader;
import io.xpipe.extension.util.XPipeDaemon; import io.xpipe.extension.util.XPipeDaemon;
@ -51,10 +52,9 @@ open module io.xpipe.extension {
uses io.xpipe.extension.DataStoreProvider; uses io.xpipe.extension.DataStoreProvider;
uses XPipeDaemon; uses XPipeDaemon;
uses io.xpipe.extension.Cache; uses io.xpipe.extension.Cache;
uses io.xpipe.extension.DataSourceActionProvider;
uses ProxyFunction; uses ProxyFunction;
uses ActionProvider; uses ActionProvider;
uses io.xpipe.extension.util.ModuleLayerLoader; uses io.xpipe.extension.util.ModuleLayerLoader;
provides ModuleLayerLoader with DataSourceTarget.Loader; provides ModuleLayerLoader with DataSourceTarget.Loader, ActionProvider.Loader, PrefsProvider.Loader;
} }