diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java index 898fb55db..1891a36ce 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntrySection.java @@ -25,19 +25,15 @@ public class StoreEntrySection implements StorageFilter.Filterable { } public static ObservableList createTopLevels() { - var topLevel = BindingsHelper.mappedContentBinding( - StoreViewState.get() - .getAllEntries() - .filtered(storeEntryWrapper -> - !storeEntryWrapper.getEntry().getState().isUsable() - || storeEntryWrapper - .getEntry() - .getProvider() - .getParent(storeEntryWrapper - .getEntry() - .getStore()) - == null), - storeEntryWrapper -> create(storeEntryWrapper)); + var filtered = BindingsHelper.filteredContentBinding( + StoreViewState.get().getAllEntries(), + storeEntryWrapper -> !storeEntryWrapper.getEntry().getState().isUsable() + || storeEntryWrapper + .getEntry() + .getProvider() + .getParent(storeEntryWrapper.getEntry().getStore()) + == null); + var topLevel = BindingsHelper.mappedContentBinding(filtered, storeEntryWrapper -> create(storeEntryWrapper)); var ordered = BindingsHelper.orderedContentBinding( topLevel, Comparator.comparing(storeEntrySection -> @@ -51,16 +47,15 @@ public class StoreEntrySection implements StorageFilter.Filterable { return new StoreEntrySection(e, FXCollections.observableArrayList()); } - var children = BindingsHelper.mappedContentBinding( - StoreViewState.get() - .getAllEntries() - .filtered(other -> other.getEntry().getState().isUsable() - && e.getEntry() - .getStore() - .equals(other.getEntry() - .getProvider() - .getParent(other.getEntry().getStore()))), - entry1 -> create(entry1)); + var filtered = BindingsHelper.filteredContentBinding( + StoreViewState.get().getAllEntries(), + other -> other.getEntry().getState().isUsable() + && e.getEntry() + .getStore() + .equals(other.getEntry() + .getProvider() + .getParent(other.getEntry().getStore()))); + var children = BindingsHelper.mappedContentBinding(filtered, entry1 -> create(entry1)); var ordered = BindingsHelper.orderedContentBinding( children, Comparator.comparing(storeEntrySection -> @@ -94,7 +89,9 @@ public class StoreEntrySection implements StorageFilter.Filterable { storeEntrySection.entry.lastAccessProperty().getValue())); var shown = BindingsHelper.filteredContentBinding( all, - StoreViewState.get().getFilterString().map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); + StoreViewState.get() + .getFilterString() + .map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s)))); var content = new ListBoxViewComp<>(shown, all, (StoreEntrySection e) -> { return e.comp(false).apply(GrowAugment.create(true, false)); }) diff --git a/app/src/main/java/io/xpipe/app/core/App.java b/app/src/main/java/io/xpipe/app/core/App.java index 20ed9dab7..8671987d3 100644 --- a/app/src/main/java/io/xpipe/app/core/App.java +++ b/app/src/main/java/io/xpipe/app/core/App.java @@ -80,12 +80,12 @@ public class App extends Application { appWindow.show(); // For demo purposes - if (true) { - stage.setX(310); - stage.setY(178); - stage.setWidth(1300); - stage.setHeight(730); - } +// if (true) { +// stage.setX(310); +// stage.setY(178); +// stage.setWidth(1300); +// stage.setHeight(730); +// } } public void focus() { diff --git a/app/src/main/java/io/xpipe/app/core/AppGreetings.java b/app/src/main/java/io/xpipe/app/core/AppGreetings.java index 9fe9e7562..7778bea35 100644 --- a/app/src/main/java/io/xpipe/app/core/AppGreetings.java +++ b/app/src/main/java/io/xpipe/app/core/AppGreetings.java @@ -90,6 +90,7 @@ public class AppGreetings { label.setGraphic(cb); AppFont.medium(label); label.setPadding(new Insets(40, 0, 10, 0)); + label.setOnMouseClicked(event -> accepted.set(!accepted.get())); return label; }) .createRegion(); diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java index 9b9d53d81..4973d6527 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java @@ -54,28 +54,23 @@ public abstract class ExternalApplicationType implements PrefsChoiceValue { } } - public static class LinuxPathApplication extends ExternalApplicationType { + public static abstract class PathApplication extends ExternalApplicationType { - protected final String command; + protected final String executable; - public LinuxPathApplication(String id, String command) { + public PathApplication(String id, String executable) { super(id); - this.command = command; + this.executable = executable; } public boolean isAvailable() { try (ShellProcessControl pc = ShellStore.local().create().start()) { - return pc.executeBooleanSimpleCommand(pc.getShellType().getWhichCommand(command)); + return pc.executeBooleanSimpleCommand(pc.getShellType().getWhichCommand(executable)); } catch (Exception e) { ErrorEvent.fromThrowable(e).omit().handle(); return false; } } - - @Override - public boolean isSelectable() { - return OsType.getLocal().equals(OsType.LINUX); - } } public abstract static class WindowsFullPathType extends ExternalApplicationType { diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java index 93488551f..5e0dad7b6 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java @@ -109,7 +109,7 @@ public interface ExternalEditorType extends PrefsChoiceValue { public void launch(Path file) throws Exception; - public static class LinuxPathType extends ExternalApplicationType.LinuxPathApplication implements ExternalEditorType { + public static class LinuxPathType extends ExternalApplicationType.PathApplication implements ExternalEditorType { public LinuxPathType(String id, String command) { super(id, command); @@ -117,9 +117,14 @@ public interface ExternalEditorType extends PrefsChoiceValue { @Override public void launch(Path file) throws IOException { - var list = ShellTypes.getPlatformDefault().executeCommandListWithShell(command + " \"" + file + "\""); + var list = ShellTypes.getPlatformDefault().executeCommandListWithShell(executable + " \"" + file + "\""); new ProcessBuilder(list).start(); } + + @Override + public boolean isSelectable() { + return OsType.getLocal().equals(OsType.LINUX); + } } public abstract static class WindowsFullPathType extends ExternalApplicationType.WindowsFullPathType implements ExternalEditorType { @@ -174,7 +179,7 @@ public interface ExternalEditorType extends PrefsChoiceValue { var env = System.getenv("VISUAL"); if (env != null) { var found = LINUX_EDITORS.stream() - .filter(externalEditorType -> externalEditorType.command.equalsIgnoreCase(env)) + .filter(externalEditorType -> externalEditorType.executable.equalsIgnoreCase(env)) .findFirst() .orElse(null); if (found == null) { diff --git a/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties b/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties index 577e76229..a32724d53 100644 --- a/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties +++ b/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties @@ -69,6 +69,14 @@ recentlyUsed=Recently used programmingLanguages=Programming languages applications=Applications addMore=Add more +vscode=Visual Studio Code +kate=Kate +gedit=GEdit +leafpad=Leafpad +mousepad=Mousepad +pluma=Pluma +textEdit=Text Edit +sublime=Sublime Text newTable=new_table unknown=Unknown editRaw=Edit Raw diff --git a/app/src/main/resources/io/xpipe/app/resources/misc/eula.md b/app/src/main/resources/io/xpipe/app/resources/misc/eula.md index b2541e2be..789fbcb3e 100644 --- a/app/src/main/resources/io/xpipe/app/resources/misc/eula.md +++ b/app/src/main/resources/io/xpipe/app/resources/misc/eula.md @@ -46,15 +46,10 @@ specific information we send, please visit https://xpipe.io/privacy_policy. You 1. **Automatic Software Updates.** The Software communicates with its server (and sends information described at the URL above) to determine whether there are any patches, bug fixes, updates, upgrades or other modifications to improve the Software. You agree that the Software may automatically install any such improvements to the Software on your - computer without providing any further notice or receiving any additional consent. This feature may not be disabled. - If you do not want to receive automatic updates, you must uninstall the Software. + computer without providing any further notice or receiving any additional consent. This feature may be disabled. 2. **Error Reports.** In order to help us improve the Software, when the Software encounters certain errors, it will automatically send some information to its server about the error (as described at the URL above). This feature may - not be disabled. If you do not want to send error reports to its server, you must uninstall the Software. -3. **Anonymized Usage Data.** X-Pipe collects anonymized data about your usage of the Software to help us make it more - awesome. Approximately once a day the Software sends such data (as described in more detail at the URL above) to its - server. If you do not want to send anonymized usage data to the server, you may opt out by changing your settings in - the Preferences view. + be disabled. ### Open-Source Notices diff --git a/app/src/main/resources/io/xpipe/app/resources/misc/welcome.md b/app/src/main/resources/io/xpipe/app/resources/misc/welcome.md index 32f2920f1..75da7c8c8 100644 --- a/app/src/main/resources/io/xpipe/app/resources/misc/welcome.md +++ b/app/src/main/resources/io/xpipe/app/resources/misc/welcome.md @@ -1,14 +1,9 @@ ## Welcome to X-Pipe! -X-Pipe (short for eXtended Pipe) is a tool that enables a fast and an efficient data transfer/exchange between -all types of producers and consumers of data, e.g. different file types, -applications, programming languages, databases, technologies, and more. +Thank you for trying out the X-Pipe Alpha. +You can overview the development status, report issues, and more at the following places: -It is currently in early development and this build is an alpha version. -A lot of features are incomplete or bugged. -You can overview and contribute to the development here: - -#### [Issue Tracker](https://github.com/xpipe-io/xpipe/issues) +#### [GitHub Repository](https://github.com/xpipe-io/xpipe/) #### [Discord Server](https://discord.gg/8y89vS8cRb) diff --git a/extension/src/main/java/io/xpipe/extension/fxcomps/util/BindingsHelper.java b/extension/src/main/java/io/xpipe/extension/fxcomps/util/BindingsHelper.java index 465746c27..0a26128ad 100644 --- a/extension/src/main/java/io/xpipe/extension/fxcomps/util/BindingsHelper.java +++ b/extension/src/main/java/io/xpipe/extension/fxcomps/util/BindingsHelper.java @@ -1,10 +1,14 @@ package io.xpipe.extension.fxcomps.util; +import io.xpipe.extension.util.ThreadHelper; import javafx.beans.binding.Binding; +import javafx.beans.binding.ListBinding; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import lombok.Value; import java.lang.ref.WeakReference; import java.util.*; @@ -14,6 +18,37 @@ import java.util.function.Predicate; public class BindingsHelper { + private static final Set REFERENCES = Collections.newSetFromMap(new ConcurrentHashMap()); + + @Value + private static class ReferenceEntry { + + WeakReference source; + Object target; + + public boolean canGc() { + return source.get() == null; + } + } + + static { + ThreadHelper.create("referenceGC", true, () -> { + while (true) { + for (ReferenceEntry reference : REFERENCES) { + if (reference.canGc()) { + REFERENCES.remove(reference); + } + } + ThreadHelper.sleep(1000); + } + }) + .start(); + } + + public static void linkPersistently(Object source, Object target) { + REFERENCES.add(new ReferenceEntry(new WeakReference<>(source), target)); + } + /* TODO: Proper cleanup. Maybe with a separate thread? */ @@ -30,6 +65,17 @@ public class BindingsHelper { return binding; } + public static > T persist(T binding) { + var dependencies = new HashSet(); + while (dependencies.addAll(binding.getDependencies().stream() + .map(o -> (javafx.beans.Observable) o) + .toList())) { + } + dependencies.add(binding); + BINDINGS.put(new WeakReference<>(binding), dependencies); + return binding; + } + public static void bindContent(ObservableList l1, ObservableList l2) { setContent(l1, l2); l2.addListener((ListChangeListener) c -> { @@ -56,6 +102,7 @@ public class BindingsHelper { l2.addListener((ListChangeListener) c -> { runnable.run(); }); + linkPersistently(l2, l1); return l1; } @@ -68,9 +115,14 @@ public class BindingsHelper { l2.addListener((ListChangeListener) c -> { runnable.run(); }); + linkPersistently(l2, l1); return l1; } + public static ObservableList filteredContentBinding(ObservableList l2,Predicate predicate) { + return filteredContentBinding(l2, new SimpleObjectProperty<>(predicate)); + } + public static ObservableList filteredContentBinding(ObservableList l2, ObservableValue> predicate) { ObservableList l1 = FXCollections.observableList(new ArrayList<>()); Runnable runnable = () -> { @@ -83,6 +135,7 @@ public class BindingsHelper { predicate.addListener((c,o,n) -> { runnable.run(); }); + linkPersistently(l2, l1); return l1; }