diff --git a/app/src/main/java/io/xpipe/app/comp/about/BrowseDirectoryComp.java b/app/src/main/java/io/xpipe/app/comp/about/BrowseDirectoryComp.java index 63ff5ec6f..a8260a3cb 100644 --- a/app/src/main/java/io/xpipe/app/comp/about/BrowseDirectoryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/about/BrowseDirectoryComp.java @@ -2,7 +2,7 @@ package io.xpipe.app.comp.about; import io.xpipe.app.comp.base.ButtonComp; 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.core.util.XPipeInstallation; import io.xpipe.extension.I18n; @@ -30,7 +30,7 @@ public class BrowseDirectoryComp extends SimpleComp { .addComp( "logFile", 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) .addComp( diff --git a/app/src/main/java/io/xpipe/app/comp/about/UpdateCheckComp.java b/app/src/main/java/io/xpipe/app/comp/about/UpdateCheckComp.java index 58db0d704..a9989b6a9 100644 --- a/app/src/main/java/io/xpipe/app/comp/about/UpdateCheckComp.java +++ b/app/src/main/java/io/xpipe/app/comp/about/UpdateCheckComp.java @@ -2,7 +2,7 @@ package io.xpipe.app.comp.about; import io.xpipe.extension.util.XPipeDistributionType; 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.extension.I18n; import io.xpipe.extension.fxcomps.SimpleComp; diff --git a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java index 807e0af2e..7c2484109 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java @@ -1,6 +1,6 @@ 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.SimpleComp; import io.xpipe.extension.fxcomps.impl.IconButtonComp; @@ -45,7 +45,7 @@ public class IntegratedTextAreaComp extends SimpleComp { } 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) -> { Platform.runLater(() -> value.setValue(s)); })).createRegion(); diff --git a/app/src/main/java/io/xpipe/app/comp/source/GuiDsStoreSelectStep.java b/app/src/main/java/io/xpipe/app/comp/source/GuiDsStoreSelectStep.java index 4776f8f44..2efc4102c 100644 --- a/app/src/main/java/io/xpipe/app/comp/source/GuiDsStoreSelectStep.java +++ b/app/src/main/java/io/xpipe/app/comp/source/GuiDsStoreSelectStep.java @@ -3,7 +3,6 @@ package io.xpipe.app.comp.source; import io.xpipe.app.comp.base.MultiStepComp; import io.xpipe.app.comp.source.store.DsDbStoreChooserComp; import io.xpipe.app.comp.source.store.DsStreamStoreChoiceComp; -import io.xpipe.app.util.Hyperlinks; import io.xpipe.core.source.DataSource; import io.xpipe.core.store.DataStore; import io.xpipe.extension.DataSourceProvider; @@ -42,7 +41,7 @@ public class GuiDsStoreSelectStep extends MultiStepComp.Step> baseSource, BooleanProperty loading) { - super(Hyperlinks.openLink(Hyperlinks.DOCS_DATA_INPUT)); + super(null); this.parent = parent; this.provider = provider; this.input = input; diff --git a/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryContextMenu.java b/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryContextMenu.java index 2b7b41a67..009411e38 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryContextMenu.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryContextMenu.java @@ -33,12 +33,15 @@ public class SourceEntryContextMenu> extends PopupMen AppFont.normal(cm.getStyleableNode()); for (var actionProvider : entry.getActionProviders()) { - var name = actionProvider.getName(entry.getEntry().getSource().asNeeded()); - var icon = actionProvider.getIcon(entry.getEntry().getSource().asNeeded()); + var c = actionProvider.getDataSourceCallSite(); + var name = c.getName(entry.getEntry().getSource().asNeeded()); + var icon = c.getIcon(entry.getEntry().getSource().asNeeded()); var item = new MenuItem(null, new FontIcon(icon)); item.setOnAction(event -> { + event.consume(); try { - actionProvider.execute(entry.getEntry().getSource().asNeeded()); + var action = c.createAction(entry.getEntry().getSource().asNeeded()); + action.execute(); } catch (Exception e) { ErrorEvent.fromThrowable(e).handle(); } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryWrapper.java b/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryWrapper.java index 310d4f977..f15e112e8 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/source/SourceEntryWrapper.java @@ -4,16 +4,17 @@ import io.xpipe.app.comp.source.GuiDsCreatorMultiStep; import io.xpipe.app.comp.storage.StorageFilter; import io.xpipe.app.comp.storage.collection.SourceCollectionViewState; 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.store.DataFlow; -import io.xpipe.extension.DataSourceActionProvider; import io.xpipe.extension.DataStoreProviders; import io.xpipe.extension.I18n; import io.xpipe.extension.event.ErrorEvent; import io.xpipe.extension.fxcomps.util.PlatformThread; +import io.xpipe.extension.util.ActionProvider; import javafx.beans.property.*; -import javafx.collections.FXCollections; import lombok.Value; import java.time.Instant; @@ -29,13 +30,10 @@ public class SourceEntryWrapper implements StorageFilter.Filterable { StringProperty information = new SimpleStringProperty(); StringProperty storeSummary = new SimpleStringProperty(); Property lastUsed = new SimpleObjectProperty<>(); - Property accessMode = new SimpleObjectProperty<>(); Property dataFlow = new SimpleObjectProperty<>(); ObjectProperty state = new SimpleObjectProperty<>(); BooleanProperty loading = new SimpleBooleanProperty(); - - List> actionProviders = new ArrayList<>(); - ListProperty accesses = new SimpleListProperty<>(FXCollections.observableArrayList()); + List actionProviders = new ArrayList<>(); public SourceEntryWrapper(DataSourceEntry entry) { this.entry = entry; @@ -100,16 +98,21 @@ public class SourceEntryWrapper implements StorageFilter.Filterable { loading.setValue(entry.getState() == null || entry.getState() == DataSourceEntry.State.VALIDATING); actionProviders.clear(); - actionProviders.addAll(DataSourceActionProvider.ALL.stream() + actionProviders.addAll(ActionProvider.ALL.stream() .filter(p -> { try { if (!entry.getState().isUsable()) { return false; } - return p.getApplicableClass() + var c = p.getDataSourceCallSite(); + if (c == null) { + return false; + } + + return c.getApplicableClass() .isAssignableFrom(entry.getSource().getClass()) - && p.isApplicable(entry.getSource().asNeeded()); + && c.isApplicable(entry.getSource().asNeeded()); } catch (Exception e) { ErrorEvent.fromThrowable(e).handle(); return false; diff --git a/app/src/main/java/io/xpipe/app/comp/storage/source/SourceStorageEmptyIntroComp.java b/app/src/main/java/io/xpipe/app/comp/storage/source/SourceStorageEmptyIntroComp.java index c3fb8271d..6ab640fd8 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/source/SourceStorageEmptyIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/source/SourceStorageEmptyIntroComp.java @@ -45,9 +45,9 @@ public class SourceStorageEmptyIntroComp extends SimpleComp { documentation.heightProperty().addListener((c, o, n) -> { dfi.iconSizeProperty().set(n.intValue()); }); - var docLink = new Hyperlink(Hyperlinks.DOCS_GETTING_STARTED); + var docLink = new Hyperlink(Hyperlinks.DOCUMENTATION); docLink.setOnAction(e -> { - Hyperlinks.open(Hyperlinks.DOCS_GETTING_STARTED); + Hyperlinks.open(Hyperlinks.DOCUMENTATION); }); var docLinkPane = new StackPane(docLink); docLinkPane.setAlignment(Pos.CENTER); diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreStorageEmptyIntroComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreStorageEmptyIntroComp.java index 99d3454a8..523573427 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreStorageEmptyIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreStorageEmptyIntroComp.java @@ -51,9 +51,9 @@ public class StoreStorageEmptyIntroComp extends SimpleComp { documentation.heightProperty().addListener((c, o, n) -> { dofi.iconSizeProperty().set(n.intValue()); }); - var docLink = new Hyperlink(Hyperlinks.DOCS_GETTING_STARTED); + var docLink = new Hyperlink(Hyperlinks.DOCUMENTATION); docLink.setOnAction(e -> { - Hyperlinks.open(Hyperlinks.DOCS_GETTING_STARTED); + Hyperlinks.open(Hyperlinks.DOCUMENTATION); }); var docLinkPane = new StackPane(docLink); docLinkPane.setAlignment(Pos.CENTER); diff --git a/app/src/main/java/io/xpipe/app/core/AppCache.java b/app/src/main/java/io/xpipe/app/core/AppCache.java index 20962adda..edc000c60 100644 --- a/app/src/main/java/io/xpipe/app/core/AppCache.java +++ b/app/src/main/java/io/xpipe/app/core/AppCache.java @@ -1,6 +1,6 @@ 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.extension.Cache; import io.xpipe.extension.event.ErrorEvent; @@ -49,7 +49,7 @@ public class AppCache implements Cache { var path = getPath(key); if (Files.exists(path)) { try { - var tree = ConfigHelper.readConfig(path); + var tree = JsonConfigHelper.readConfig(path); if (tree.isMissingNode()) { return notPresent.get(); } @@ -69,7 +69,7 @@ public class AppCache implements Cache { try { FileUtils.forceMkdirParent(path.toFile()); var tree = JacksonMapper.newMapper().valueToTree(val); - ConfigHelper.writeConfig(path, tree); + JsonConfigHelper.writeConfig(path, tree); } catch (Exception e) { ErrorEvent.fromThrowable("Could not parse cached data for key " + key, e) .omitted(true) diff --git a/app/src/main/java/io/xpipe/app/core/AppI18n.java b/app/src/main/java/io/xpipe/app/core/AppI18n.java index e5533366f..deb18eeb8 100644 --- a/app/src/main/java/io/xpipe/app/core/AppI18n.java +++ b/app/src/main/java/io/xpipe/app/core/AppI18n.java @@ -4,11 +4,16 @@ import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.SupportedLocale; import io.xpipe.app.util.ModuleHelper; import io.xpipe.extension.I18n; +import io.xpipe.extension.Translatable; import io.xpipe.extension.event.ErrorEvent; 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.StringBinding; import javafx.beans.value.ObservableValue; +import lombok.SneakyThrows; import org.apache.commons.io.FilenameUtils; import org.ocpsoft.prettytime.PrettyTime; @@ -89,11 +94,31 @@ public class AppI18n implements I18n { 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 public String getKey(String s) { var key = s; if (!s.contains(".")) { - key = ModuleHelper.getCallerModuleName() + "." + s; + key = getCallerModuleName() + "." + s; } return key; } diff --git a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java index 8c45b526b..82de23a7e 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java @@ -3,8 +3,8 @@ package io.xpipe.app.core.mode; import io.xpipe.app.comp.storage.collection.SourceCollectionViewState; import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.core.*; -import io.xpipe.app.editor.EditorState; -import io.xpipe.app.grid.AppUpdater; +import io.xpipe.app.util.ExternalEditor; +import io.xpipe.app.update.AppUpdater; import io.xpipe.app.issue.BasicErrorHandler; import io.xpipe.app.issue.ErrorHandler; import io.xpipe.app.prefs.AppPrefs; @@ -40,7 +40,7 @@ public class BaseMode extends OperationMode { AppCharsetter.init(); DataStorage.init(); FileWatchManager.init(); - EditorState.init(); + ExternalEditor.init(); AppSocketServer.init(); AppUpdater.init(); TrackEvent.info("mode", "Finished base components initialization"); diff --git a/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java b/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java index 7e895c919..1b7cd6028 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java @@ -1,6 +1,6 @@ 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.AppGreetings; import io.xpipe.app.issue.ErrorHandler; diff --git a/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java b/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java index ad2b55eaa..af2f7f34e 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java @@ -3,7 +3,7 @@ package io.xpipe.app.core.mode; import io.xpipe.app.comp.storage.collection.SourceCollectionViewState; import io.xpipe.app.comp.storage.store.StoreViewState; 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.util.ThreadHelper; import javafx.application.Application; diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java index 1728c2e1e..c85e6b636 100644 --- a/app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java @@ -1,7 +1,7 @@ package io.xpipe.app.exchange.cli; 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.exchange.cli.InstanceExchange; import io.xpipe.core.impl.LocalStore; diff --git a/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java b/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java index 5969f4326..1f693026e 100644 --- a/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java +++ b/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java @@ -3,7 +3,7 @@ package io.xpipe.app.issue; import io.sentry.Sentry; import io.xpipe.app.core.*; 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.event.ErrorEvent; import javafx.application.Platform; diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java index a1485d7b9..23e9d67aa 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -16,6 +16,7 @@ import io.xpipe.extension.prefs.PrefsChoiceValue; import io.xpipe.extension.prefs.PrefsHandler; import io.xpipe.extension.prefs.PrefsProvider; import io.xpipe.extension.util.XPipeDistributionType; +import javafx.beans.binding.Bindings; import javafx.beans.property.*; import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableValue; @@ -26,6 +27,24 @@ import java.util.*; 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 tooltipDelayMax = 1500; private static final int fontSizeMin = 10; @@ -134,7 +153,7 @@ public class AppPrefs { private final ObjectProperty effectiveStorageDirectory = STORAGE_DIR_FIXED ? new SimpleObjectProperty<>(AppProperties.get().getDataDir().resolve("storage")) : internalStorageDirectory; - private final StringField storageDirectoryControl = Fields.ofPath(effectiveStorageDirectory) + private final StringField storageDirectoryControl = PrefFields.ofPath(effectiveStorageDirectory) .editable(!STORAGE_DIR_FIXED) .validate( CustomValidators.absolutePath(), @@ -230,24 +249,24 @@ public class AppPrefs { return effectiveDeveloperMode; } - public ReadOnlyBooleanProperty developerDisableUpdateVersionCheck() { - return developerDisableUpdateVersionCheck; + public ObservableBooleanValue developerDisableUpdateVersionCheck() { + return bindDeveloperTrue(developerDisableUpdateVersionCheck); } - public ReadOnlyBooleanProperty developerDisableGuiRestrictions() { - return developerDisableGuiRestrictions; + public ObservableBooleanValue developerDisableGuiRestrictions() { + return bindDeveloperTrue(developerDisableGuiRestrictions); } - public ReadOnlyBooleanProperty developerDisableConnectorInstallationVersionCheck() { - return developerDisableConnectorInstallationVersionCheck; + public ObservableBooleanValue developerDisableConnectorInstallationVersionCheck() { + return bindDeveloperTrue(developerDisableConnectorInstallationVersionCheck); } - public ReadOnlyBooleanProperty developerShowHiddenProviders() { - return developerShowHiddenProviders; + public ObservableBooleanValue developerShowHiddenProviders() { + return bindDeveloperTrue(developerShowHiddenProviders); } - public ReadOnlyBooleanProperty developerShowHiddenEntries() { - return developerShowHiddenEntries; + public ObservableBooleanValue developerShowHiddenEntries() { + return bindDeveloperTrue(developerShowHiddenEntries); } private AppPreferencesFx preferencesFx; diff --git a/app/src/main/java/io/xpipe/app/prefs/JsonStorageHandler.java b/app/src/main/java/io/xpipe/app/prefs/JsonStorageHandler.java index b29eb35a3..317ea5bc2 100644 --- a/app/src/main/java/io/xpipe/app/prefs/JsonStorageHandler.java +++ b/app/src/main/java/io/xpipe/app/prefs/JsonStorageHandler.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; import com.fasterxml.jackson.databind.type.CollectionType; 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.extension.event.ErrorEvent; import io.xpipe.extension.event.TrackEvent; @@ -32,7 +32,7 @@ public class JsonStorageHandler implements StorageHandler { private JsonNode getContent(String key) { if (content == null) { - content = (ObjectNode) ConfigHelper.readConfig(file); + content = (ObjectNode) JsonConfigHelper.readConfig(file); } return content.get(key); } @@ -42,7 +42,7 @@ public class JsonStorageHandler implements StorageHandler { } void save() { - ConfigHelper.writeConfig(file, content); + JsonConfigHelper.writeConfig(file, content); } @Override diff --git a/app/src/main/java/io/xpipe/app/prefs/Fields.java b/app/src/main/java/io/xpipe/app/prefs/PrefFields.java similarity index 97% rename from app/src/main/java/io/xpipe/app/prefs/Fields.java rename to app/src/main/java/io/xpipe/app/prefs/PrefFields.java index b03b4d3a0..7b786fd6f 100644 --- a/app/src/main/java/io/xpipe/app/prefs/Fields.java +++ b/app/src/main/java/io/xpipe/app/prefs/PrefFields.java @@ -11,7 +11,7 @@ import javafx.util.StringConverter; import java.nio.file.Path; import java.util.Objects; -public class Fields { +public class PrefFields { public static StringField ofPath(ObjectProperty fileProperty) { StringProperty stringProperty = new SimpleStringProperty(); diff --git a/app/src/main/java/io/xpipe/app/storage/AccessMode.java b/app/src/main/java/io/xpipe/app/storage/AccessMode.java deleted file mode 100644 index 8fb0d7fea..000000000 --- a/app/src/main/java/io/xpipe/app/storage/AccessMode.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.xpipe.app.storage; - -public enum AccessMode { - READ, - WRITE -} diff --git a/app/src/main/java/io/xpipe/app/storage/ApplicationAccess.java b/app/src/main/java/io/xpipe/app/storage/ApplicationAccess.java deleted file mode 100644 index 07c0d79aa..000000000 --- a/app/src/main/java/io/xpipe/app/storage/ApplicationAccess.java +++ /dev/null @@ -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) {} diff --git a/app/src/main/java/io/xpipe/app/grid/AppDownloads.java b/app/src/main/java/io/xpipe/app/update/AppDownloads.java similarity index 99% rename from app/src/main/java/io/xpipe/app/grid/AppDownloads.java rename to app/src/main/java/io/xpipe/app/update/AppDownloads.java index 82e2c00c5..693b7ec65 100644 --- a/app/src/main/java/io/xpipe/app/grid/AppDownloads.java +++ b/app/src/main/java/io/xpipe/app/update/AppDownloads.java @@ -1,4 +1,4 @@ -package io.xpipe.app.grid; +package io.xpipe.app.update; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.extension.event.ErrorEvent; diff --git a/app/src/main/java/io/xpipe/app/grid/AppInstaller.java b/app/src/main/java/io/xpipe/app/update/AppInstaller.java similarity index 94% rename from app/src/main/java/io/xpipe/app/grid/AppInstaller.java rename to app/src/main/java/io/xpipe/app/update/AppInstaller.java index c37e63b9c..9b062db98 100644 --- a/app/src/main/java/io/xpipe/app/grid/AppInstaller.java +++ b/app/src/main/java/io/xpipe/app/update/AppInstaller.java @@ -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.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; +import io.xpipe.app.util.TerminalProvider; import io.xpipe.core.impl.FileNames; -import io.xpipe.core.impl.LocalProcessControlProvider; import io.xpipe.core.process.CommandProcessControl; import io.xpipe.core.process.OsType; 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" + "DEBIAN_FRONTEND=noninteractive sudo apt-get install -qy \"" + file + "\"\n" + "xpipe daemon start"; - var script = ScriptHelper.createLocalExecScript(command); - LocalProcessControlProvider.get().openInTerminal("X-Pipe Updater", script); + TerminalProvider.open("X-Pipe Updater", command); } } @@ -223,8 +222,7 @@ public class AppInstaller { @Override public void installLocal(String file) throws Exception { var command = "set -x\n" + "sudo rpm -U -v --force \"" + file + "\"\n" + "xpipe daemon start"; - var script = ScriptHelper.createLocalExecScript(command); - LocalProcessControlProvider.get().openInTerminal("X-Pipe Updater", script); + TerminalProvider.open("X-Pipe Updater", command); } } @@ -250,8 +248,7 @@ public class AppInstaller { @Override public void installLocal(String file) throws Exception { var command = "set -x\n" + "sudo installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /\n" + "xpipe daemon start"; - var script = ScriptHelper.createLocalExecScript(command); - LocalProcessControlProvider.get().openInTerminal("X-Pipe Updater", script); + TerminalProvider.open("X-Pipe Updater", command); } } } diff --git a/app/src/main/java/io/xpipe/app/grid/AppUpdater.java b/app/src/main/java/io/xpipe/app/update/AppUpdater.java similarity index 98% rename from app/src/main/java/io/xpipe/app/grid/AppUpdater.java rename to app/src/main/java/io/xpipe/app/update/AppUpdater.java index c908b7b24..9d3aa8487 100644 --- a/app/src/main/java/io/xpipe/app/grid/AppUpdater.java +++ b/app/src/main/java/io/xpipe/app/update/AppUpdater.java @@ -1,4 +1,4 @@ -package io.xpipe.app.grid; +package io.xpipe.app.update; import io.xpipe.app.core.AppCache; 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.mode.OperationMode; 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.extension.event.ErrorEvent; import io.xpipe.extension.event.TrackEvent; @@ -112,7 +112,7 @@ public class AppUpdater { if (layer == null) { return; } - LocalProcessControlProvider.init(layer); + ProcessControlProvider.init(layer); INSTANCE = new AppUpdater(); } diff --git a/app/src/main/java/io/xpipe/app/grid/UpdateAvailableAlert.java b/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java similarity index 96% rename from app/src/main/java/io/xpipe/app/grid/UpdateAvailableAlert.java rename to app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java index cd5f88e32..3a6b80ab4 100644 --- a/app/src/main/java/io/xpipe/app/grid/UpdateAvailableAlert.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java @@ -1,4 +1,4 @@ -package io.xpipe.app.grid; +package io.xpipe.app.update; import io.xpipe.app.core.AppWindowHelper; import io.xpipe.extension.I18n; diff --git a/app/src/main/java/io/xpipe/app/grid/UpdateChangelogAlert.java b/app/src/main/java/io/xpipe/app/update/UpdateChangelogAlert.java similarity index 97% rename from app/src/main/java/io/xpipe/app/grid/UpdateChangelogAlert.java rename to app/src/main/java/io/xpipe/app/update/UpdateChangelogAlert.java index 61b83c952..61e4dba54 100644 --- a/app/src/main/java/io/xpipe/app/grid/UpdateChangelogAlert.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateChangelogAlert.java @@ -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.core.AppWindowHelper; diff --git a/app/src/main/java/io/xpipe/app/storage/XPipeInstanceHelper.java b/app/src/main/java/io/xpipe/app/update/XPipeInstanceHelper.java similarity index 97% rename from app/src/main/java/io/xpipe/app/storage/XPipeInstanceHelper.java rename to app/src/main/java/io/xpipe/app/update/XPipeInstanceHelper.java index 776401186..700e77c34 100644 --- a/app/src/main/java/io/xpipe/app/storage/XPipeInstanceHelper.java +++ b/app/src/main/java/io/xpipe/app/update/XPipeInstanceHelper.java @@ -1,6 +1,7 @@ -package io.xpipe.app.storage; +package io.xpipe.app.update; import io.xpipe.app.core.AppProperties; +import io.xpipe.app.storage.DataStorage; import io.xpipe.beacon.XPipeInstance; import io.xpipe.core.store.ShellStore; import io.xpipe.extension.event.ErrorEvent; diff --git a/app/src/main/java/io/xpipe/app/util/AskpassAlert.java b/app/src/main/java/io/xpipe/app/util/AskpassAlert.java deleted file mode 100644 index a47c8fb0b..000000000 --- a/app/src/main/java/io/xpipe/app/util/AskpassAlert.java +++ /dev/null @@ -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 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; - } -} diff --git a/app/src/main/java/io/xpipe/app/util/DeveloperHelper.java b/app/src/main/java/io/xpipe/app/util/DeveloperHelper.java deleted file mode 100644 index d27f1a300..000000000 --- a/app/src/main/java/io/xpipe/app/util/DeveloperHelper.java +++ /dev/null @@ -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()); - } -} diff --git a/app/src/main/java/io/xpipe/app/editor/EditorState.java b/app/src/main/java/io/xpipe/app/util/ExternalEditor.java similarity index 97% rename from app/src/main/java/io/xpipe/app/editor/EditorState.java rename to app/src/main/java/io/xpipe/app/util/ExternalEditor.java index fd24c24df..598c83b36 100644 --- a/app/src/main/java/io/xpipe/app/editor/EditorState.java +++ b/app/src/main/java/io/xpipe/app/util/ExternalEditor.java @@ -1,4 +1,4 @@ -package io.xpipe.app.editor; +package io.xpipe.app.util; import io.xpipe.app.core.FileWatchManager; import io.xpipe.app.prefs.AppPrefs; @@ -22,14 +22,14 @@ import java.util.UUID; import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Consumer; -public class EditorState { +public class ExternalEditor { private static final Path TEMP = FileUtils.getTempDirectory().toPath().resolve("xpipe").resolve("editor"); - private static EditorState INSTANCE; + private static ExternalEditor INSTANCE; private final Set openEntries = new CopyOnWriteArraySet<>(); - public static EditorState get() { + public static ExternalEditor get() { return INSTANCE; } @@ -42,7 +42,7 @@ public class EditorState { } public static void init() { - INSTANCE = new EditorState(); + INSTANCE = new ExternalEditor(); try { FileUtils.forceMkdir(TEMP.toFile()); diff --git a/app/src/main/java/io/xpipe/app/util/FlexmarkHelper.java b/app/src/main/java/io/xpipe/app/util/FlexmarkHelper.java deleted file mode 100644 index 6ddaa5088..000000000 --- a/app/src/main/java/io/xpipe/app/util/FlexmarkHelper.java +++ /dev/null @@ -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 readEntities(InputStream stream) { - Map 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; - } -} diff --git a/app/src/main/java/io/xpipe/app/util/Hyperlinks.java b/app/src/main/java/io/xpipe/app/util/Hyperlinks.java index 51c9268ed..6b6fa0842 100644 --- a/app/src/main/java/io/xpipe/app/util/Hyperlinks.java +++ b/app/src/main/java/io/xpipe/app/util/Hyperlinks.java @@ -9,17 +9,12 @@ import java.net.URI; public class Hyperlinks { 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 DISCORD = "https://discord.gg/8y89vS8cRb"; public static final String SLACK = "https://join.slack.com/t/x-pipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg"; - - 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 final String DOCS_PRIVACY = "https://xpipe.io/docs/privacy"; public static Runnable openLink(String s) { return () -> open(s); diff --git a/app/src/main/java/io/xpipe/app/util/ConfigHelper.java b/app/src/main/java/io/xpipe/app/util/JsonConfigHelper.java similarity index 91% rename from app/src/main/java/io/xpipe/app/util/ConfigHelper.java rename to app/src/main/java/io/xpipe/app/util/JsonConfigHelper.java index ae77c0eac..0c8168a98 100644 --- a/app/src/main/java/io/xpipe/app/util/ConfigHelper.java +++ b/app/src/main/java/io/xpipe/app/util/JsonConfigHelper.java @@ -15,13 +15,13 @@ import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Path; -public class ConfigHelper { +public class JsonConfigHelper { public static JsonNode readConfig(Path in) { JsonNode node = JsonNodeFactory.instance.objectNode(); try { if (Files.exists(in)) { - ObjectMapper o = JacksonMapper.newMapper(); + ObjectMapper o = JacksonMapper.getDefault(); node = o.readTree(Files.readAllBytes(in)); } } catch (IOException e) { @@ -41,7 +41,7 @@ public class ConfigHelper { var writer = new StringWriter(); JsonFactory f = new JsonFactory(); try (JsonGenerator g = f.createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter())) { - JacksonMapper.newMapper().writeTree(g, node); + JacksonMapper.getDefault().writeTree(g, node); var newContent = writer.toString(); Files.writeString(out, newContent); } catch (IOException e) { diff --git a/app/src/main/java/io/xpipe/app/util/ModuleHelper.java b/app/src/main/java/io/xpipe/app/util/ModuleHelper.java index 9a857a627..04c87b6a3 100644 --- a/app/src/main/java/io/xpipe/app/util/ModuleHelper.java +++ b/app/src/main/java/io/xpipe/app/util/ModuleHelper.java @@ -1,11 +1,5 @@ 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 java.lang.reflect.Field; @@ -13,26 +7,6 @@ import java.lang.reflect.Method; 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() { return ModuleHelper.class .getProtectionDomain() diff --git a/app/src/main/java/io/xpipe/app/util/ProxyManagerProviderImpl.java b/app/src/main/java/io/xpipe/app/util/ProxyManagerProviderImpl.java index a14ac913a..efd981017 100644 --- a/app/src/main/java/io/xpipe/app/util/ProxyManagerProviderImpl.java +++ b/app/src/main/java/io/xpipe/app/util/ProxyManagerProviderImpl.java @@ -2,8 +2,8 @@ package io.xpipe.app.util; import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppWindowHelper; -import io.xpipe.app.grid.AppDownloads; -import io.xpipe.app.grid.AppInstaller; +import io.xpipe.app.update.AppDownloads; +import io.xpipe.app.update.AppInstaller; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.impl.FileNames; import io.xpipe.core.process.ShellProcessControl; diff --git a/app/src/main/java/io/xpipe/app/util/TerminalProvider.java b/app/src/main/java/io/xpipe/app/util/TerminalProvider.java new file mode 100644 index 000000000..517e53952 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/util/TerminalProvider.java @@ -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; +} diff --git a/app/src/main/java/io/xpipe/app/util/XPipeDaemonProvider.java b/app/src/main/java/io/xpipe/app/util/XPipeDaemonProvider.java index 8c4fa8f98..1fc2a3724 100644 --- a/app/src/main/java/io/xpipe/app/util/XPipeDaemonProvider.java +++ b/app/src/main/java/io/xpipe/app/util/XPipeDaemonProvider.java @@ -7,7 +7,7 @@ import io.xpipe.app.comp.source.store.NamedStoreChoiceComp; import io.xpipe.app.core.AppImages; import io.xpipe.app.core.AppProperties; 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.DataStoreEntry; import io.xpipe.core.charsetter.Charsetter; diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index 46b62ff63..726b2513d 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -27,8 +27,7 @@ open module io.xpipe.app { exports io.xpipe.app.prefs; exports io.xpipe.app.comp.source.store; exports io.xpipe.app.storage; - exports io.xpipe.app.editor; - exports io.xpipe.app.grid; + exports io.xpipe.app.update; exports io.xpipe.app.comp.storage; exports io.xpipe.app.comp.storage.collection; @@ -98,6 +97,7 @@ open module io.xpipe.app { requires jdk.jdwp.agent; uses MessageExchangeImpl; + uses io.xpipe.app.util.TerminalProvider; provides DataStateProvider with DataStateProviderImpl; diff --git a/core/src/main/java/io/xpipe/core/impl/LocalProcessControlProvider.java b/core/src/main/java/io/xpipe/core/impl/LocalProcessControlProvider.java deleted file mode 100644 index 1c1c94650..000000000 --- a/core/src/main/java/io/xpipe/core/impl/LocalProcessControlProvider.java +++ /dev/null @@ -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; -} diff --git a/core/src/main/java/io/xpipe/core/impl/LocalStore.java b/core/src/main/java/io/xpipe/core/impl/LocalStore.java index a5f33f213..2ebc97326 100644 --- a/core/src/main/java/io/xpipe/core/impl/LocalStore.java +++ b/core/src/main/java/io/xpipe/core/impl/LocalStore.java @@ -48,7 +48,7 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac @Override public ShellProcessControl create() { - return LocalProcessControlProvider.create(); + return ProcessControlProvider.createLocal(); } } diff --git a/core/src/main/java/io/xpipe/core/impl/ProcessControlProvider.java b/core/src/main/java/io/xpipe/core/impl/ProcessControlProvider.java new file mode 100644 index 000000000..1eff1f093 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/impl/ProcessControlProvider.java @@ -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 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 commandFunction, + BiFunction terminalCommand) { + return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.sub(parent, commandFunction, terminalCommand)).findFirst().orElseThrow(); + } + + public static CommandProcessControl createCommand( + ShellProcessControl parent, + @NonNull Function command, + Function terminalCommand) { + return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.command(parent, command, terminalCommand)).findFirst().orElseThrow(); + } + + public abstract ShellProcessControl sub( + ShellProcessControl parent, + @NonNull Function commandFunction, + BiFunction terminalCommand); + + public abstract CommandProcessControl command( + ShellProcessControl parent, + @NonNull Function command, + Function terminalCommand); + + public abstract ShellProcessControl createLocalProcessControl(); +} diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index 506da871a..4caf80884 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -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.util.CoreJacksonModule; @@ -24,7 +24,7 @@ open module io.xpipe.core { uses com.fasterxml.jackson.databind.Module; uses io.xpipe.core.source.WriteMode; - uses LocalProcessControlProvider; + uses ProcessControlProvider; uses io.xpipe.core.util.ProxyProvider; uses io.xpipe.core.util.ProxyManagerProvider; uses io.xpipe.core.util.DataStateProvider; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java b/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java index 25815429b..be7c93f83 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java @@ -1,6 +1,6 @@ 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.LocalStore; import io.xpipe.core.store.DataFlow; @@ -33,9 +33,9 @@ public class FileEditAction implements DataStoreActionProvider { @Override public void execute(FileStore store) throws Exception { if (store.getFileSystem().equals(new LocalStore())) { - EditorState.get().openInEditor(store.getFile()); + ExternalEditor.get().openInEditor(store.getFile()); } else { - EditorState.get() + ExternalEditor.get() .startEditing(store.getFileName(), store.getFileExtension(), store, () -> store.openInput(), () -> store.openOutput()); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/apps/CommandLineTarget.java b/ext/base/src/main/java/io/xpipe/ext/base/apps/CommandLineTarget.java index c522752b6..c28765f23 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/apps/CommandLineTarget.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/apps/CommandLineTarget.java @@ -57,7 +57,7 @@ public class CommandLineTarget implements DataSourceTarget { @Override 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 diff --git a/ext/base/src/main/java/io/xpipe/ext/base/apps/JavaTarget.java b/ext/base/src/main/java/io/xpipe/ext/base/apps/JavaTarget.java index 82b99d95a..4481b6ecf 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/apps/JavaTarget.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/apps/JavaTarget.java @@ -118,6 +118,6 @@ public class JavaTarget implements DataSourceTarget { @Override public String getSetupGuideURL() { - return "https://docs.xpipe.io/en/latest/api/java.html"; + return "https://xpipe.io/docs/en/latest/api/java.html"; } } diff --git a/ext/base/src/test/java/test/TextFileTest.java b/ext/base/src/test/java/test/TextFileTest.java index c09898ffa..df7194994 100644 --- a/ext/base/src/test/java/test/TextFileTest.java +++ b/ext/base/src/test/java/test/TextFileTest.java @@ -5,7 +5,7 @@ import io.xpipe.core.charsetter.NewLine; import io.xpipe.core.charsetter.StreamCharset; import io.xpipe.core.impl.FileStore; 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.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/ext/csv/src/test/java/io/xpipe/ext/csv/test/CsvDetectorTest.java b/ext/csv/src/test/java/io/xpipe/ext/csv/test/CsvDetectorTest.java index e0a70e0c5..ec758d7ac 100644 --- a/ext/csv/src/test/java/io/xpipe/ext/csv/test/CsvDetectorTest.java +++ b/ext/csv/src/test/java/io/xpipe/ext/csv/test/CsvDetectorTest.java @@ -5,7 +5,7 @@ import io.xpipe.core.data.node.ValueNode; import io.xpipe.ext.csv.CsvDelimiter; import io.xpipe.ext.csv.CsvHeaderState; 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.Test; diff --git a/extension/src/main/java/io/xpipe/extension/DataSourceActionProvider.java b/extension/src/main/java/io/xpipe/extension/DataSourceActionProvider.java deleted file mode 100644 index 8a8842145..000000000 --- a/extension/src/main/java/io/xpipe/extension/DataSourceActionProvider.java +++ /dev/null @@ -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> { - - static List> 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 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 getName(T store); - - String getIcon(T store); - - default void execute(T store) throws Exception { - } -} diff --git a/extension/src/main/java/io/xpipe/extension/DataSourceTarget.java b/extension/src/main/java/io/xpipe/extension/DataSourceTarget.java index 37899c746..ef2d88fd8 100644 --- a/extension/src/main/java/io/xpipe/extension/DataSourceTarget.java +++ b/extension/src/main/java/io/xpipe/extension/DataSourceTarget.java @@ -31,6 +31,11 @@ public interface DataSourceTarget { public boolean requiresFullDaemon() { return true; } + + @Override + public boolean prioritizeLoading() { + return false; + } } public static Optional byId(String id) { diff --git a/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java b/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java index 7148b11ad..ae10f8a63 100644 --- a/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java +++ b/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java @@ -1,19 +1,19 @@ package io.xpipe.extension; 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.ProxyFunction; 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.XPipeDaemon; public class XPipeServiceProviders { 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 ..."); DataSourceProviders.init(layer); @@ -34,14 +34,10 @@ public class XPipeServiceProviders { }); } - var hasDaemon = XPipeDaemon.getInstanceIfPresent().isPresent(); - ModuleLayerLoader.loadAll(layer, hasDaemon); + ModuleLayerLoader.loadAll(layer, hasDaemon, false); if (hasDaemon) { - ActionProvider.init(layer); - DataSourceActionProvider.init(layer); ProxyFunction.init(layer); - PrefsProvider.init(layer); } TrackEvent.info("Finished loading extension providers"); diff --git a/extension/src/main/java/io/xpipe/extension/prefs/PrefsProvider.java b/extension/src/main/java/io/xpipe/extension/prefs/PrefsProvider.java index d235e794d..c23b90fad 100644 --- a/extension/src/main/java/io/xpipe/extension/prefs/PrefsProvider.java +++ b/extension/src/main/java/io/xpipe/extension/prefs/PrefsProvider.java @@ -1,6 +1,7 @@ package io.xpipe.extension.prefs; import com.dlsc.formsfx.model.structure.Field; +import io.xpipe.extension.util.ModuleLayerLoader; import javafx.beans.value.ObservableBooleanValue; import java.util.ServiceLoader; @@ -11,12 +12,24 @@ public abstract class PrefsProvider { private static Set ALL; - public static void init(ModuleLayer layer) { - if (ALL == null) { + public static class Loader implements ModuleLayerLoader { + + @Override + public void init(ModuleLayer layer) { ALL = ServiceLoader.load(layer, PrefsProvider.class).stream() .map(ServiceLoader.Provider::get) .collect(Collectors.toSet()); } + + @Override + public boolean requiresFullDaemon() { + return true; + } + + @Override + public boolean prioritizeLoading() { + return false; + } } public static Set getAll() { diff --git a/extension/src/main/java/io/xpipe/extension/util/DaemonExtensionTest.java b/extension/src/main/java/io/xpipe/extension/test/DaemonExtensionTest.java similarity index 97% rename from extension/src/main/java/io/xpipe/extension/util/DaemonExtensionTest.java rename to extension/src/main/java/io/xpipe/extension/test/DaemonExtensionTest.java index 43ae403ee..b0a7f7447 100644 --- a/extension/src/main/java/io/xpipe/extension/util/DaemonExtensionTest.java +++ b/extension/src/main/java/io/xpipe/extension/test/DaemonExtensionTest.java @@ -1,4 +1,4 @@ -package io.xpipe.extension.util; +package io.xpipe.extension.test; import io.xpipe.api.DataSource; import io.xpipe.beacon.BeaconDaemonController; diff --git a/extension/src/main/java/io/xpipe/extension/util/ExtensionTest.java b/extension/src/main/java/io/xpipe/extension/test/ExtensionTest.java similarity index 97% rename from extension/src/main/java/io/xpipe/extension/util/ExtensionTest.java rename to extension/src/main/java/io/xpipe/extension/test/ExtensionTest.java index e66e2e05b..dc445fc39 100644 --- a/extension/src/main/java/io/xpipe/extension/util/ExtensionTest.java +++ b/extension/src/main/java/io/xpipe/extension/test/ExtensionTest.java @@ -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.impl.FileStore; diff --git a/extension/src/main/java/io/xpipe/extension/util/LocalExtensionTest.java b/extension/src/main/java/io/xpipe/extension/test/LocalExtensionTest.java similarity index 93% rename from extension/src/main/java/io/xpipe/extension/util/LocalExtensionTest.java rename to extension/src/main/java/io/xpipe/extension/test/LocalExtensionTest.java index 0291dd9b8..92e89b15c 100644 --- a/extension/src/main/java/io/xpipe/extension/util/LocalExtensionTest.java +++ b/extension/src/main/java/io/xpipe/extension/test/LocalExtensionTest.java @@ -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.XPipeSession; diff --git a/extension/src/main/java/io/xpipe/extension/util/ActionProvider.java b/extension/src/main/java/io/xpipe/extension/util/ActionProvider.java index cb8189231..791f730ca 100644 --- a/extension/src/main/java/io/xpipe/extension/util/ActionProvider.java +++ b/extension/src/main/java/io/xpipe/extension/util/ActionProvider.java @@ -1,5 +1,6 @@ package io.xpipe.extension.util; +import io.xpipe.core.source.DataSource; import io.xpipe.core.store.DataStore; import io.xpipe.extension.event.ErrorEvent; import javafx.beans.value.ObservableValue; @@ -7,24 +8,37 @@ import javafx.beans.value.ObservableValue; import java.util.ArrayList; import java.util.List; import java.util.ServiceLoader; +import java.util.stream.Collectors; public interface ActionProvider { static List ALL = new ArrayList<>(); - public static void init(ModuleLayer layer) { - if (ALL.size() == 0) { + public static class Loader implements ModuleLayerLoader { + + @Override + public void init(ModuleLayer layer) { ALL.addAll(ServiceLoader.load(layer, ActionProvider.class).stream() - .map(p -> (ActionProvider) p.get()) - .filter(provider -> { - try { - return provider.isActive(); - } catch (Throwable e) { - ErrorEvent.fromThrowable(e).handle(); - return false; - } - }) - .toList()); + .map(actionProviderProvider -> actionProviderProvider.get()) + .filter(provider -> { + try { + return provider.isActive(); + } catch (Throwable e) { + ErrorEvent.fromThrowable(e).handle(); + return false; + } + }) + .collect(Collectors.toSet())); + } + + @Override + public boolean requiresFullDaemon() { + return true; + } + + @Override + public boolean prioritizeLoading() { + return false; } } @@ -39,10 +53,9 @@ public interface ActionProvider { return true; } - interface LauncherCallSite { - String getId(); + String getId(); Action createAction(List args) throws Exception; } @@ -55,6 +68,11 @@ public interface ActionProvider { return null; } + default DataSourceCallSite getDataSourceCallSite() { + return null; + } + + public static interface DataStoreCallSite { Action createAction(T store); @@ -64,6 +82,7 @@ public interface ActionProvider { default boolean isMajor() { return false; } + default boolean isApplicable(T o) throws Exception { return true; } @@ -76,4 +95,27 @@ public interface ActionProvider { return true; } } + + public static interface DataSourceCallSite> { + + Action createAction(T source); + + Class getApplicableClass(); + + default boolean isMajor() { + return false; + } + + default boolean isApplicable(T o) throws Exception { + return true; + } + + ObservableValue getName(T source); + + String getIcon(T source); + + default boolean showIfDisabled() { + return true; + } + } } diff --git a/extension/src/main/java/io/xpipe/extension/util/ModuleLayerLoader.java b/extension/src/main/java/io/xpipe/extension/util/ModuleLayerLoader.java index 323c5ab98..2276098cd 100644 --- a/extension/src/main/java/io/xpipe/extension/util/ModuleLayerLoader.java +++ b/extension/src/main/java/io/xpipe/extension/util/ModuleLayerLoader.java @@ -6,13 +6,18 @@ import java.util.ServiceLoader; 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 -> { var instance = moduleLayerLoaderProvider.get(); try { if (instance.requiresFullDaemon() && !hasDaemon) { return; } + + if (instance.prioritizeLoading() != prioritization) { + return; + } + instance.init(layer); } catch (Throwable t) { ErrorEvent.fromThrowable(t).handle(); @@ -23,4 +28,6 @@ public interface ModuleLayerLoader { public void init(ModuleLayer layer); boolean requiresFullDaemon(); + + boolean prioritizeLoading(); } diff --git a/extension/src/main/java/module-info.java b/extension/src/main/java/module-info.java index d2a5744d4..93e7d11bc 100644 --- a/extension/src/main/java/module-info.java +++ b/extension/src/main/java/module-info.java @@ -2,6 +2,7 @@ import io.xpipe.core.util.ProxyFunction; import io.xpipe.extension.DataSourceProvider; import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.DataSourceTarget; +import io.xpipe.extension.prefs.PrefsProvider; import io.xpipe.extension.util.ActionProvider; import io.xpipe.extension.util.ModuleLayerLoader; import io.xpipe.extension.util.XPipeDaemon; @@ -51,10 +52,9 @@ open module io.xpipe.extension { uses io.xpipe.extension.DataStoreProvider; uses XPipeDaemon; uses io.xpipe.extension.Cache; - uses io.xpipe.extension.DataSourceActionProvider; uses ProxyFunction; uses ActionProvider; uses io.xpipe.extension.util.ModuleLayerLoader; - provides ModuleLayerLoader with DataSourceTarget.Loader; + provides ModuleLayerLoader with DataSourceTarget.Loader, ActionProvider.Loader, PrefsProvider.Loader; }