diff --git a/core/src/main/java/io/xpipe/core/store/DataStore.java b/core/src/main/java/io/xpipe/core/store/DataStore.java index bf616dce..ba94f68b 100644 --- a/core/src/main/java/io/xpipe/core/store/DataStore.java +++ b/core/src/main/java/io/xpipe/core/store/DataStore.java @@ -16,6 +16,15 @@ import java.util.Optional; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") public interface DataStore { + default boolean isComplete() { + try { + checkComplete(); + return true; + } catch (Exception ignored) { + return false; + } + } + default DataFlow getFlow() { return DataFlow.INPUT_OUTPUT; } diff --git a/core/src/main/java/io/xpipe/core/store/FileStore.java b/core/src/main/java/io/xpipe/core/store/FileStore.java index 9188c4ed..b49ccfc5 100644 --- a/core/src/main/java/io/xpipe/core/store/FileStore.java +++ b/core/src/main/java/io/xpipe/core/store/FileStore.java @@ -27,6 +27,10 @@ public class FileStore extends JacksonizedValue implements FilenameStore, Stream this.file = file; } + public final boolean isLocal() { + return machine instanceof LocalStore; + } + public static FileStore local(Path p) { return new FileStore(new LocalStore(), p.toString()); } diff --git a/extension/src/main/java/io/xpipe/extension/DataSourceActionProvider.java b/extension/src/main/java/io/xpipe/extension/DataSourceActionProvider.java new file mode 100644 index 00000000..ffb35b17 --- /dev/null +++ b/extension/src/main/java/io/xpipe/extension/DataSourceActionProvider.java @@ -0,0 +1,49 @@ +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 (Exception 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/XPipeServiceProviders.java b/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java index 2e4ac521..7218cd1e 100644 --- a/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java +++ b/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java @@ -28,6 +28,7 @@ public class XPipeServiceProviders { } DataStoreActionProvider.init(layer); + DataSourceActionProvider.init(layer); SupportedApplicationProviders.loadAll(layer); PrefsProviders.init(layer); diff --git a/extension/src/main/java/io/xpipe/extension/comp/WriteModeChoiceComp.java b/extension/src/main/java/io/xpipe/extension/comp/WriteModeChoiceComp.java index 4472fc5e..fb3bcf78 100644 --- a/extension/src/main/java/io/xpipe/extension/comp/WriteModeChoiceComp.java +++ b/extension/src/main/java/io/xpipe/extension/comp/WriteModeChoiceComp.java @@ -49,10 +49,14 @@ public class WriteModeChoiceComp extends SimpleComp implements Validatable { PlatformThread.sync(available).addListener((ListChangeListener) c -> { var newMap = new LinkedHashMap>(); - for (WriteMode writeMode : a) { + for (WriteMode writeMode : c.getList()) { newMap.put(writeMode,I18n.observable(writeMode.getId())); } map.setValue(newMap); + + if (c.getList().size() == 1) { + selected.setValue(c.getList().get(0)); + } }); return new ToggleGroupComp<>(selected, map) diff --git a/extension/src/main/java/io/xpipe/extension/util/BusyProperty.java b/extension/src/main/java/io/xpipe/extension/util/BusyProperty.java new file mode 100644 index 00000000..0b7a42d4 --- /dev/null +++ b/extension/src/main/java/io/xpipe/extension/util/BusyProperty.java @@ -0,0 +1,18 @@ +package io.xpipe.extension.util; + +import javafx.beans.property.BooleanProperty; + +public class BusyProperty implements AutoCloseable { + + private final BooleanProperty prop; + + public BusyProperty(BooleanProperty prop) { + this.prop = prop; + prop.setValue(true); + } + + @Override + public void close() { + prop.setValue(false); + } +} diff --git a/extension/src/main/java/io/xpipe/extension/util/OsHelper.java b/extension/src/main/java/io/xpipe/extension/util/OsHelper.java index 98f15fc5..57f3b58a 100644 --- a/extension/src/main/java/io/xpipe/extension/util/OsHelper.java +++ b/extension/src/main/java/io/xpipe/extension/util/OsHelper.java @@ -21,7 +21,7 @@ public class OsHelper { } } - public static void browseFile(Path file) { + public static void browsePath(Path file) { if (!Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) { return; } diff --git a/extension/src/main/java/io/xpipe/extension/util/SupportedOs.java b/extension/src/main/java/io/xpipe/extension/util/SupportedOs.java new file mode 100644 index 00000000..f929c037 --- /dev/null +++ b/extension/src/main/java/io/xpipe/extension/util/SupportedOs.java @@ -0,0 +1,75 @@ +package io.xpipe.extension.util; + +import org.apache.commons.lang3.SystemUtils; + +import java.nio.file.Path; +import java.util.UUID; + +public interface SupportedOs { + + Windows WINDOWS = new Windows(); + Linux LINUX = new Linux(); + Mac MAC = new Mac(); + + public static SupportedOs get() { + if (SystemUtils.IS_OS_WINDOWS) { + return WINDOWS; + } else if (SystemUtils.IS_OS_LINUX) { + return LINUX; + } else if (SystemUtils.IS_OS_MAC) { + return MAC; + } else { + throw new UnsupportedOperationException("Unsupported operating system"); + } + } + + Path getBaseInstallPath(); + + UUID getSystemUUID(); + + static class Windows implements SupportedOs { + + @Override + public Path getBaseInstallPath() { + return Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe"); + } + + @Override + public UUID getSystemUUID() { + var s = WindowsRegistry.readRegistry( + "Computer\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography", "MachineGuid") + .orElse(null); + if (s == null) { + return null; + } + + return UUID.fromString(s); + } + } + + static class Linux implements SupportedOs { + + @Override + public Path getBaseInstallPath() { + return Path.of("/opt/xpipe"); + } + + @Override + public UUID getSystemUUID() { + return null; + } + } + + static class Mac implements SupportedOs { + + @Override + public Path getBaseInstallPath() { + return Path.of(System.getProperty("user.home"), "Application Support", "X-Pipe"); + } + + @Override + public UUID getSystemUUID() { + return null; + } + } +} diff --git a/extension/src/main/java/io/xpipe/extension/util/WindowsRegistry.java b/extension/src/main/java/io/xpipe/extension/util/WindowsRegistry.java new file mode 100644 index 00000000..dfc89167 --- /dev/null +++ b/extension/src/main/java/io/xpipe/extension/util/WindowsRegistry.java @@ -0,0 +1,60 @@ +package io.xpipe.extension.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.util.Optional; + +public class WindowsRegistry { + + public static Optional readRegistry(String location, String key) { + try { + Process process = + Runtime.getRuntime().exec("reg query " + '"' + location + "\"" + (key != null ? " /v " + key : " /ve")); + + StreamReader reader = new StreamReader(process.getInputStream()); + reader.start(); + process.waitFor(); + reader.join(); + String output = reader.getResult(); + + // Output has the following format: + // \n\n\n\t\t + if (output.contains("\t")) { + String[] parsed = output.split("\t"); + return Optional.of(parsed[parsed.length - 1]); + } + + if (output.contains(" ")) { + String[] parsed = output.split(" "); + return Optional.of(parsed[parsed.length - 1].substring(0, parsed[parsed.length - 1].length() - 4)); + } + + return Optional.empty(); + } catch (Exception e) { + return Optional.empty(); + } + } + + static class StreamReader extends Thread { + private final InputStream is; + private final StringWriter sw = new StringWriter(); + + public StreamReader(InputStream is) { + this.is = is; + } + + public void run() { + try { + int c; + while ((c = is.read()) != -1) sw.write(c); + } catch (IOException e) { + System.err.println(e.toString()); + } + } + + public String getResult() { + return sw.toString(); + } + } +} \ No newline at end of file diff --git a/extension/src/main/java/module-info.java b/extension/src/main/java/module-info.java index 8088b0f7..1aafebe2 100644 --- a/extension/src/main/java/module-info.java +++ b/extension/src/main/java/module-info.java @@ -39,4 +39,5 @@ open module io.xpipe.extension { uses io.xpipe.extension.DataStoreProvider; uses XPipeDaemon; uses io.xpipe.extension.Cache; + uses io.xpipe.extension.DataSourceActionProvider; }