Polish various features

This commit is contained in:
crschnick 2023-02-03 18:07:02 +00:00
parent c0abdf968a
commit 6263b791cf
12 changed files with 181 additions and 161 deletions

View file

@ -25,19 +25,15 @@ public class StoreEntrySection implements StorageFilter.Filterable {
}
public static ObservableList<StoreEntrySection> 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.<StoreEntrySection, Instant>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.<StoreEntrySection, Instant>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));
})

View file

@ -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() {

View file

@ -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();

View file

@ -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 {

View file

@ -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) {

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -1,5 +1,6 @@
package io.xpipe.ext.proc;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellProcessControl;
import io.xpipe.core.store.ShellStore;
@ -7,18 +8,12 @@ import io.xpipe.extension.event.ErrorEvent;
import io.xpipe.extension.prefs.PrefsChoiceValue;
import io.xpipe.extension.prefs.PrefsProvider;
import io.xpipe.extension.util.ApplicationHelper;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
@Getter
@AllArgsConstructor
public abstract class TerminalType implements PrefsChoiceValue {
public interface ExternalTerminalType extends PrefsChoiceValue {
public static final TerminalType CMD = new SimpleType("proc.cmd", "cmd", "cmd.exe") {
public static final ExternalTerminalType CMD = new SimpleType("proc.cmd", "cmd", "cmd.exe") {
@Override
protected String toCommand(String name, String command) {
@ -31,7 +26,7 @@ public abstract class TerminalType implements PrefsChoiceValue {
}
};
public static final TerminalType POWERSHELL = new SimpleType("proc.powershell", "powershell", "PowerShell") {
public static final ExternalTerminalType POWERSHELL = new SimpleType("proc.powershell", "powershell", "PowerShell") {
@Override
protected String toCommand(String name, String command) {
@ -44,7 +39,7 @@ public abstract class TerminalType implements PrefsChoiceValue {
}
};
public static final TerminalType WINDOWS_TERMINAL =
public static final ExternalTerminalType WINDOWS_TERMINAL =
new SimpleType("proc.windowsTerminal", "wt.exe", "Windows Terminal") {
@Override
@ -58,7 +53,7 @@ public abstract class TerminalType implements PrefsChoiceValue {
}
};
public static final TerminalType GNOME_TERMINAL =
public static final ExternalTerminalType GNOME_TERMINAL =
new SimpleType("proc.gnomeTerminal", "gnome-terminal", "Gnome Terminal") {
@Override
@ -72,7 +67,7 @@ public abstract class TerminalType implements PrefsChoiceValue {
}
};
public static final TerminalType KONSOLE = new SimpleType("proc.konsole", "konsole", "Konsole") {
public static final ExternalTerminalType KONSOLE = new SimpleType("proc.konsole", "konsole", "Konsole") {
@Override
protected String toCommand(String name, String command) {
@ -85,7 +80,7 @@ public abstract class TerminalType implements PrefsChoiceValue {
}
};
public static final TerminalType XFCE = new SimpleType("proc.xfce", "xfce4-terminal", "Xfce") {
public static final ExternalTerminalType XFCE = new SimpleType("proc.xfce", "xfce4-terminal", "Xfce") {
@Override
protected String toCommand(String name, String command) {
@ -98,38 +93,15 @@ public abstract class TerminalType implements PrefsChoiceValue {
}
};
public static final TerminalType MACOS_TERMINAL = new MacType("proc.macosTerminal", "Terminal");
public static final ExternalTerminalType MACOS_TERMINAL = new MacOsType();
public static final TerminalType ITERM2 = new ITerm2Type();
public static final ExternalTerminalType ITERM2 = new ITerm2Type();
public static final TerminalType WARP = new WarpType();
public static final ExternalTerminalType WARP = new WarpType();
public static final TerminalType CUSTOM = new TerminalType("app.custom") {
public static final ExternalTerminalType CUSTOM = new CustomType();
@Override
public void launch(String name, String command) throws Exception {
var custom =
PrefsProvider.get(ProcPrefs.class).customTerminalCommand().getValue();
if (custom == null || custom.trim().isEmpty()) {
return;
}
var format = custom.contains("$cmd") ? custom : custom + " $cmd";
ShellStore.local().create().executeSimpleCommand(format.replace("$cmd", command));
}
@Override
public boolean isSelectable() {
return true;
}
@Override
public boolean isAvailable() {
return false;
}
};
public static final List<TerminalType> ALL = List.of(
public static final List<ExternalTerminalType> ALL = List.of(
WINDOWS_TERMINAL,
POWERSHELL,
CMD,
@ -144,42 +116,60 @@ public abstract class TerminalType implements PrefsChoiceValue {
.filter(terminalType -> terminalType.isSelectable())
.toList();
public static TerminalType getDefault() {
public static ExternalTerminalType getDefault() {
return ALL.stream()
.filter(terminalType -> terminalType.isAvailable())
.findFirst()
.orElse(null);
}
private String id;
public abstract void launch(String name, String command) throws Exception;
public abstract boolean isSelectable();
static class MacOsType extends ExternalApplicationType.MacApplication implements ExternalTerminalType {
public abstract boolean isAvailable();
public MacOsType() {
super("proc.macosTerminal", "Terminal");
}
static class MacType extends TerminalType {
@Override
public void launch(String name, String command) throws Exception {
var custom =
PrefsProvider.get(ProcPrefs.class).customTerminalCommand().getValue();
if (custom == null || custom.trim().isEmpty()) {
return;
}
private final String terminalName;
var format = custom.contains("$cmd") ? custom : custom + " $cmd";
try (var pc = ShellStore.local().create().start()) {
var toExecute = format.replace("$cmd", command);
if (pc.getOsType().equals(OsType.WINDOWS)) {
toExecute = "start \"" + name + "\" " + toExecute;
} else {
toExecute = "nohup " + toExecute + " </dev/null &>/dev/null & disown";
}
pc.executeSimpleCommand(toExecute);
}
}
}
public MacType(String id, String terminalName) {
super(id);
this.terminalName = terminalName;
static class CustomType extends ExternalApplicationType implements ExternalTerminalType {
public CustomType() {
super("proc.custom");
}
@Override
public void launch(String name, String command) throws Exception {
try (ShellProcessControl pc = ShellStore.local().create().start()) {
var suffix = command.equals(pc.getShellType().getNormalOpenCommand()) ? "\"\"" : "\"" + command + "\"";
var cmd = "osascript -e 'tell app \"" + terminalName + "\" to do script " + suffix + "'";
var cmd = "osascript -e 'tell app \"" + "Terminal" + "\" to do script " + suffix + "'";
pc.executeSimpleCommand(cmd);
}
}
@Override
public boolean isSelectable() {
return OsType.getLocal().equals(OsType.MAC);
return true;
}
@Override
@ -188,10 +178,10 @@ public abstract class TerminalType implements PrefsChoiceValue {
}
}
static class ITerm2Type extends TerminalType {
static class ITerm2Type extends ExternalApplicationType.MacApplication implements ExternalTerminalType {
public ITerm2Type() {
super("proc.iterm2");
super("proc.iterm2", "iTerm2");
}
@Override
@ -200,7 +190,6 @@ public abstract class TerminalType implements PrefsChoiceValue {
var cmd = String.format(
"""
osascript - "$@" <<EOF
on run argv
tell application "iTerm"
activate
set new_term to (create window with profile "Default" command "%s")
@ -211,22 +200,12 @@ public abstract class TerminalType implements PrefsChoiceValue {
pc.executeSimpleCommand(cmd);
}
}
@Override
public boolean isSelectable() {
return OsType.getLocal().equals(OsType.MAC);
}
@Override
public boolean isAvailable() {
return Files.exists(Path.of("/Applications/iTerm2.app"));
}
}
static class WarpType extends TerminalType {
static class WarpType extends ExternalApplicationType.MacApplication implements ExternalTerminalType {
public WarpType() {
super("proc.warp");
super("proc.warp", "Warp");
}
@Override
@ -234,41 +213,30 @@ public abstract class TerminalType implements PrefsChoiceValue {
try (ShellProcessControl pc = ShellStore.local().create().start()) {
var cmd = String.format(
"""
osascript - "$@" <<EOF
tell application "Warp" to activate'
sudo osascript -e 'tell application "System Events" to tell process "Warp" to keystroke "t" using command down'
sleep 1
sudo osascript -e 'tell application "System Events"
tell process "Warp"
keystroke "%s"
key code 36
end tell
end tell
EOF""",
osascript - "$@" <<EOF
tell application "Warp" to activate
tell application "System Events" to tell process "Warp" to keystroke "t" using command down
delay 1
tell application "System Events"
tell process "Warp"
keystroke "%s"
key code 36
end tell
end tell
EOF
""",
command);
pc.executeSimpleCommand(cmd);
}
}
@Override
public boolean isSelectable() {
return OsType.getLocal().equals(OsType.MAC);
}
@Override
public boolean isAvailable() {
return Files.exists(Path.of("/Applications/iTerm2.app"));
}
}
public abstract static class SimpleType extends TerminalType {
public abstract static class SimpleType extends ExternalApplicationType.PathApplication implements ExternalTerminalType {
private final String executable;
private final String displayName;
public SimpleType(String id, String executable, String displayName) {
super(id);
this.executable = executable;
super(id, executable);
this.displayName = displayName;
}

View file

@ -25,10 +25,10 @@ public class ProcPrefs extends PrefsProvider {
return enableCaching;
}
private final ObjectProperty<TerminalType> terminalType = new SimpleObjectProperty<>();
private final SimpleListProperty<TerminalType> terminalTypeList = new SimpleListProperty<>(
FXCollections.observableArrayList(PrefsChoiceValue.getSupported(TerminalType.class)));
private final SingleSelectionField<TerminalType> terminalTypeControl = Field.ofSingleSelectionType(
private final ObjectProperty<ExternalTerminalType> terminalType = new SimpleObjectProperty<>();
private final SimpleListProperty<ExternalTerminalType> terminalTypeList = new SimpleListProperty<>(
FXCollections.observableArrayList(PrefsChoiceValue.getSupported(ExternalTerminalType.class)));
private final SingleSelectionField<ExternalTerminalType> terminalTypeControl = Field.ofSingleSelectionType(
terminalTypeList, terminalType)
.render(() -> new TranslatableComboBoxControl<>());
@ -37,9 +37,9 @@ public class ProcPrefs extends PrefsProvider {
private final StringProperty customTerminalCommand = new SimpleStringProperty("");
private final StringField customTerminalCommandControl = editable(
StringField.ofStringType(customTerminalCommand).render(() -> new SimpleTextControl()),
terminalType.isEqualTo(TerminalType.CUSTOM));
terminalType.isEqualTo(ExternalTerminalType.CUSTOM));
public ObservableValue<TerminalType> terminalType() {
public ObservableValue<ExternalTerminalType> terminalType() {
return terminalType;
}
@ -53,19 +53,19 @@ public class ProcPrefs extends PrefsProvider {
List.of("integrations"),
"proc.terminal",
Setting.of("app.defaultProgram", terminalTypeControl, terminalType),
TerminalType.class);
ExternalTerminalType.class);
handler.addSetting(
List.of("integrations"),
"proc.terminal",
Setting.of("proc.customTerminalCommand", customTerminalCommandControl, customTerminalCommand)
.applyVisibility(VisibilityProperty.of(terminalType.isEqualTo(TerminalType.CUSTOM))),
.applyVisibility(VisibilityProperty.of(terminalType.isEqualTo(ExternalTerminalType.CUSTOM))),
String.class);
}
@Override
public void init() {
if (terminalType.get() == null) {
terminalType.set(TerminalType.getDefault());
terminalType.set(ExternalTerminalType.getDefault());
}
}
}

View file

@ -88,4 +88,7 @@ keyPassword=Key Password
key=Key
installConnector=Install Connector
konsole=Konsole
xfce=Xfce
xfce=Xfce
macosTerminal=Terminal
iterm2=iTerm2
warp=Warp

View file

@ -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<ReferenceEntry> REFERENCES = Collections.newSetFromMap(new ConcurrentHashMap<ReferenceEntry, Boolean>());
@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 extends ListBinding<?>> T persist(T binding) {
var dependencies = new HashSet<javafx.beans.Observable>();
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 <T> void bindContent(ObservableList<T> l1, ObservableList<? extends T> l2) {
setContent(l1, l2);
l2.addListener((ListChangeListener<? super T>) c -> {
@ -56,6 +102,7 @@ public class BindingsHelper {
l2.addListener((ListChangeListener<? super V>) c -> {
runnable.run();
});
linkPersistently(l2, l1);
return l1;
}
@ -68,9 +115,14 @@ public class BindingsHelper {
l2.addListener((ListChangeListener<? super V>) c -> {
runnable.run();
});
linkPersistently(l2, l1);
return l1;
}
public static <V> ObservableList<V> filteredContentBinding(ObservableList<V> l2,Predicate<V> predicate) {
return filteredContentBinding(l2, new SimpleObjectProperty<>(predicate));
}
public static <V> ObservableList<V> filteredContentBinding(ObservableList<V> l2, ObservableValue<Predicate<V>> predicate) {
ObservableList<V> 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;
}