mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
Browser fixes
This commit is contained in:
parent
ddfa70d68b
commit
ff36cfb12a
17 changed files with 163 additions and 134 deletions
|
@ -27,7 +27,7 @@ You should therefore always check out the matching version tag for your local re
|
||||||
You can find the available version tags at https://github.com/xpipe-io/xpipe/tags.
|
You can find the available version tags at https://github.com/xpipe-io/xpipe/tags.
|
||||||
So for example if you currently have XPipe `11.3` installed, you should run `git reset --hard 11.3` first to properly compile against it.
|
So for example if you currently have XPipe `11.3` installed, you should run `git reset --hard 11.3` first to properly compile against it.
|
||||||
|
|
||||||
You need to have JDK for Java 21 installed to compile the project.
|
You need to have JDK for Java 22 installed to compile the project.
|
||||||
If you are on Linux or macOS, you can easily accomplish that by running
|
If you are on Linux or macOS, you can easily accomplish that by running
|
||||||
```bash
|
```bash
|
||||||
curl -s "https://get.sdkman.io" | bash
|
curl -s "https://get.sdkman.io" | bash
|
||||||
|
@ -57,7 +57,7 @@ to connect to that debugger through [AttachMe](https://plugins.jetbrains.com/plu
|
||||||
|
|
||||||
## Modularity and IDEs
|
## Modularity and IDEs
|
||||||
|
|
||||||
All XPipe components target [Java 21](https://openjdk.java.net/projects/jdk/21/) and make full use of the Java Module System (JPMS).
|
All XPipe components target [Java 22](https://openjdk.java.net/projects/jdk/22/) and make full use of the Java Module System (JPMS).
|
||||||
All components are modularized, including all their dependencies.
|
All components are modularized, including all their dependencies.
|
||||||
In case a dependency is (sadly) not modularized yet, module information is manually added using [extra-java-module-info](https://github.com/gradlex-org/extra-java-module-info).
|
In case a dependency is (sadly) not modularized yet, module information is manually added using [extra-java-module-info](https://github.com/gradlex-org/extra-java-module-info).
|
||||||
Further, note that as this is a pretty complicated Java project that fully utilizes modularity,
|
Further, note that as this is a pretty complicated Java project that fully utilizes modularity,
|
||||||
|
@ -65,7 +65,7 @@ many IDEs still have problems building this project properly.
|
||||||
|
|
||||||
For example, you can't build this project in eclipse or vscode as it will complain about missing modules.
|
For example, you can't build this project in eclipse or vscode as it will complain about missing modules.
|
||||||
The tested and recommended IDE is IntelliJ.
|
The tested and recommended IDE is IntelliJ.
|
||||||
When setting up the project in IntelliJ, make sure that the correct JDK (Java 21)
|
When setting up the project in IntelliJ, make sure that the correct JDK (Java 22)
|
||||||
is selected both for the project and for gradle itself.
|
is selected both for the project and for gradle itself.
|
||||||
|
|
||||||
## Contributing guide
|
## Contributing guide
|
||||||
|
|
|
@ -10,7 +10,7 @@ import io.xpipe.app.storage.DataColor;
|
||||||
public final class BrowserHomeTabModel extends BrowserSessionTab {
|
public final class BrowserHomeTabModel extends BrowserSessionTab {
|
||||||
|
|
||||||
public BrowserHomeTabModel(BrowserAbstractSessionModel<?> browserModel) {
|
public BrowserHomeTabModel(BrowserAbstractSessionModel<?> browserModel) {
|
||||||
super(browserModel, AppI18n.get("overview"), null);
|
super(browserModel, AppI18n.get("overview"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,6 +11,9 @@ import io.xpipe.app.terminal.TerminalDockComp;
|
||||||
import io.xpipe.app.terminal.TerminalDockModel;
|
import io.xpipe.app.terminal.TerminalDockModel;
|
||||||
import io.xpipe.app.terminal.TerminalView;
|
import io.xpipe.app.terminal.TerminalView;
|
||||||
import io.xpipe.app.terminal.TerminalViewInstance;
|
import io.xpipe.app.terminal.TerminalViewInstance;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
@ -23,9 +26,10 @@ public final class BrowserTerminalDockTabModel extends BrowserSessionTab {
|
||||||
private final ObservableList<UUID> terminalRequests;
|
private final ObservableList<UUID> terminalRequests;
|
||||||
private final TerminalDockModel dockModel = new TerminalDockModel();
|
private final TerminalDockModel dockModel = new TerminalDockModel();
|
||||||
private TerminalView.Listener listener;
|
private TerminalView.Listener listener;
|
||||||
|
private ObservableBooleanValue viewActive;
|
||||||
|
|
||||||
public BrowserTerminalDockTabModel(BrowserAbstractSessionModel<?> browserModel, BrowserSessionTab origin, ObservableList<UUID> terminalRequests) {
|
public BrowserTerminalDockTabModel(BrowserAbstractSessionModel<?> browserModel, BrowserSessionTab origin, ObservableList<UUID> terminalRequests) {
|
||||||
super(browserModel, AppI18n.get("terminal"), null);
|
super(browserModel, AppI18n.get("terminal"));
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
this.terminalRequests = terminalRequests;
|
this.terminalRequests = terminalRequests;
|
||||||
}
|
}
|
||||||
|
@ -84,11 +88,14 @@ public final class BrowserTerminalDockTabModel extends BrowserSessionTab {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TerminalView.get().addListener(listener);
|
TerminalView.get().addListener(listener);
|
||||||
this.browserModel.getSelectedEntry().addListener((observable, oldValue, newValue) -> {
|
|
||||||
dockModel.toggleView(newValue == origin);
|
viewActive = Bindings.createBooleanBinding(() -> {
|
||||||
});
|
return this.browserModel.getSelectedEntry().getValue() == origin && AppLayoutModel.get().getEntries().indexOf(AppLayoutModel.get().getSelected().getValue()) == 1;
|
||||||
AppLayoutModel.get().getSelected().addListener((observable, oldValue, newValue) -> {
|
}, this.browserModel.getSelectedEntry(), AppLayoutModel.get().getSelected());
|
||||||
dockModel.toggleView(AppLayoutModel.get().getEntries().indexOf(newValue) == 1);
|
viewActive.subscribe(aBoolean -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
dockModel.toggleView(aBoolean);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,6 @@ public interface LeafAction extends BrowserAction {
|
||||||
default Button toButton(Region root, OpenFileSystemModel model, List<BrowserEntry> selected) {
|
default Button toButton(Region root, OpenFileSystemModel model, List<BrowserEntry> selected) {
|
||||||
var b = new Button();
|
var b = new Button();
|
||||||
b.setOnAction(event -> {
|
b.setOnAction(event -> {
|
||||||
// Only accept shortcut actions in the current tab
|
|
||||||
if (!model.equals(model.getBrowserModel().getSelectedEntry().getValue())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadHelper.runFailableAsync(() -> {
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
BooleanScope.executeExclusive(model.getBusy(), () -> {
|
BooleanScope.executeExclusive(model.getBusy(), () -> {
|
||||||
if (model.getFileSystem() == null) {
|
if (model.getFileSystem() == null) {
|
||||||
|
|
|
@ -40,6 +40,7 @@ import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
@ -274,8 +275,15 @@ public final class BrowserFileListComp extends SimpleComp {
|
||||||
}
|
}
|
||||||
table.getSelectionModel().setCellSelectionEnabled(false);
|
table.getSelectionModel().setCellSelectionEnabled(false);
|
||||||
|
|
||||||
|
var updateFromModel = new BooleanScope(new SimpleBooleanProperty());
|
||||||
table.getSelectionModel().getSelectedItems().addListener((ListChangeListener<? super BrowserEntry>) c -> {
|
table.getSelectionModel().getSelectedItems().addListener((ListChangeListener<? super BrowserEntry>) c -> {
|
||||||
fileList.getSelection().setAll(c.getList());
|
if (updateFromModel.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (var ignored = updateFromModel) {
|
||||||
|
fileList.getSelection().setAll(c.getList());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
fileList.getSelection().addListener((ListChangeListener<? super BrowserEntry>) c -> {
|
fileList.getSelection().addListener((ListChangeListener<? super BrowserEntry>) c -> {
|
||||||
|
@ -284,16 +292,27 @@ public final class BrowserFileListComp extends SimpleComp {
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (c.getList().isEmpty()) {
|
var tableIndices = table.getSelectionModel().getSelectedItems().stream()
|
||||||
|
.mapToInt(entry -> table.getItems().indexOf(entry))
|
||||||
|
.toArray();
|
||||||
|
var indices = c.getList().stream()
|
||||||
|
.mapToInt(entry -> table.getItems().indexOf(entry))
|
||||||
|
.toArray();
|
||||||
|
if (Arrays.equals(indices, tableIndices)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indices.length == 0) {
|
||||||
table.getSelectionModel().clearSelection();
|
table.getSelectionModel().clearSelection();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var indices = c.getList().stream()
|
if (indices.length == 1) {
|
||||||
.mapToInt(entry -> table.getItems().indexOf(entry))
|
table.getSelectionModel().clearAndSelect(indices[0]);
|
||||||
.toArray();
|
} else {
|
||||||
table.getSelectionModel()
|
table.getSelectionModel().clearSelection();
|
||||||
.selectIndices(table.getItems().indexOf(c.getList().getFirst()), indices);
|
table.getSelectionModel().selectIndices(indices[0], indices);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ import io.xpipe.app.comp.store.StoreEntryWrapper;
|
||||||
import io.xpipe.app.core.AppLayoutModel;
|
import io.xpipe.app.core.AppLayoutModel;
|
||||||
import io.xpipe.app.ext.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
|
import io.xpipe.app.fxcomps.CompStructure;
|
||||||
import io.xpipe.app.fxcomps.SimpleComp;
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.impl.AnchorComp;
|
import io.xpipe.app.fxcomps.impl.AnchorComp;
|
||||||
import io.xpipe.app.fxcomps.impl.LabelComp;
|
|
||||||
import io.xpipe.app.fxcomps.impl.StackComp;
|
import io.xpipe.app.fxcomps.impl.StackComp;
|
||||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
|
@ -25,8 +25,10 @@ import javafx.beans.property.SimpleDoubleProperty;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
@ -41,6 +43,66 @@ public class BrowserSessionComp extends SimpleComp {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Region createSimple() {
|
protected Region createSimple() {
|
||||||
|
var vertical = createLeftSide();
|
||||||
|
|
||||||
|
var leftSplit = new SimpleDoubleProperty();
|
||||||
|
var rightSplit = new SimpleDoubleProperty();
|
||||||
|
var tabs = new BrowserSessionTabsComp(model, leftSplit, rightSplit);
|
||||||
|
tabs.apply(struc -> {
|
||||||
|
struc.get().setViewOrder(1);
|
||||||
|
struc.get().setPickOnBounds(false);
|
||||||
|
AnchorPane.setTopAnchor(struc.get(), 0.0);
|
||||||
|
AnchorPane.setBottomAnchor(struc.get(), 0.0);
|
||||||
|
AnchorPane.setLeftAnchor(struc.get(), 0.0);
|
||||||
|
AnchorPane.setRightAnchor(struc.get(), 0.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
vertical.apply(struc -> {
|
||||||
|
struc.get()
|
||||||
|
.paddingProperty()
|
||||||
|
.bind(Bindings.createObjectBinding(
|
||||||
|
() -> new Insets(tabs.getHeaderHeight().get(), 0, 0, 0), tabs.getHeaderHeight()));
|
||||||
|
});
|
||||||
|
var loadingIndicator = LoadingOverlayComp.noProgress(Comp.empty(), model.getBusy())
|
||||||
|
.apply(struc -> {
|
||||||
|
AnchorPane.setTopAnchor(struc.get(), 3.0);
|
||||||
|
AnchorPane.setRightAnchor(struc.get(), 0.0);
|
||||||
|
})
|
||||||
|
.styleClass("tab-loading-indicator");
|
||||||
|
|
||||||
|
var pinnedStack = createSplitStack(rightSplit, tabs);
|
||||||
|
|
||||||
|
var loadingStack = new AnchorComp(List.of(tabs, pinnedStack, loadingIndicator));
|
||||||
|
var splitPane = new LeftSplitPaneComp(vertical, loadingStack)
|
||||||
|
.withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth())
|
||||||
|
.withOnDividerChange(d -> {
|
||||||
|
AppLayoutModel.get().getSavedState().setBrowserConnectionsWidth(d);
|
||||||
|
leftSplit.set(d);
|
||||||
|
});
|
||||||
|
splitPane.apply(struc -> {
|
||||||
|
struc.getLeft().setMinWidth(200);
|
||||||
|
struc.getLeft().setMaxWidth(500);
|
||||||
|
struc.get().setPickOnBounds(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
splitPane.apply(struc -> {
|
||||||
|
struc.get().skinProperty().subscribe(newValue -> {
|
||||||
|
if (newValue != null) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
struc.get().getChildrenUnmodifiable().forEach(node -> {
|
||||||
|
node.setClip(null);
|
||||||
|
node.setPickOnBounds(false);
|
||||||
|
});
|
||||||
|
struc.get().lookupAll(".split-pane-divider").forEach(node -> node.setViewOrder(1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
splitPane.styleClass("browser");
|
||||||
|
return splitPane.createRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Comp<CompStructure<VBox>> createLeftSide() {
|
||||||
Predicate<StoreEntryWrapper> applicable = storeEntryWrapper -> {
|
Predicate<StoreEntryWrapper> applicable = storeEntryWrapper -> {
|
||||||
if (!storeEntryWrapper.getEntry().getValidity().isUsable()) {
|
if (!storeEntryWrapper.getEntry().getValidity().isUsable()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -104,42 +166,30 @@ public class BrowserSessionComp extends SimpleComp {
|
||||||
localDownloadStage.maxHeight(200);
|
localDownloadStage.maxHeight(200);
|
||||||
var vertical =
|
var vertical =
|
||||||
new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer, localDownloadStage)).styleClass("left");
|
new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer, localDownloadStage)).styleClass("left");
|
||||||
|
return vertical;
|
||||||
|
}
|
||||||
|
|
||||||
var leftSplit = new SimpleDoubleProperty();
|
private StackComp createSplitStack(SimpleDoubleProperty rightSplit, BrowserSessionTabsComp tabs) {
|
||||||
var rightSplit = new SimpleDoubleProperty();
|
var cache = new HashMap<BrowserSessionTab, Region>();
|
||||||
var tabs = new BrowserSessionTabsComp(model, leftSplit, rightSplit);
|
var pinnedStack = new StackComp(List.of());
|
||||||
tabs.apply(struc -> {
|
|
||||||
struc.get().setViewOrder(1);
|
|
||||||
struc.get().setPickOnBounds(false);
|
|
||||||
AnchorPane.setTopAnchor(struc.get(), 0.0);
|
|
||||||
AnchorPane.setBottomAnchor(struc.get(), 0.0);
|
|
||||||
AnchorPane.setLeftAnchor(struc.get(), 0.0);
|
|
||||||
AnchorPane.setRightAnchor(struc.get(), 0.0);
|
|
||||||
});
|
|
||||||
|
|
||||||
vertical.apply(struc -> {
|
|
||||||
struc.get()
|
|
||||||
.paddingProperty()
|
|
||||||
.bind(Bindings.createObjectBinding(
|
|
||||||
() -> new Insets(tabs.getHeaderHeight().get(), 0, 0, 0), tabs.getHeaderHeight()));
|
|
||||||
});
|
|
||||||
var loadingIndicator = LoadingOverlayComp.noProgress(Comp.empty(), model.getBusy())
|
|
||||||
.apply(struc -> {
|
|
||||||
AnchorPane.setTopAnchor(struc.get(), 3.0);
|
|
||||||
AnchorPane.setRightAnchor(struc.get(), 0.0);
|
|
||||||
})
|
|
||||||
.styleClass("tab-loading-indicator");
|
|
||||||
|
|
||||||
var pinnedStack = new StackComp(List.of(new LabelComp("a")));
|
|
||||||
pinnedStack.apply(struc -> {
|
pinnedStack.apply(struc -> {
|
||||||
model.getEffectiveRightTab().subscribe( (newValue) -> {
|
model.getEffectiveRightTab().subscribe( (newValue) -> {
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
if (newValue != null) {
|
var all = model.getAllTabs();
|
||||||
var r = newValue.comp().createRegion();
|
cache.keySet().removeIf(browserSessionTab -> !all.contains(browserSessionTab));
|
||||||
struc.get().getChildren().add(r);
|
|
||||||
} else {
|
if (newValue == null) {
|
||||||
struc.get().getChildren().clear();
|
struc.get().getChildren().clear();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cached = cache.containsKey(newValue);
|
||||||
|
if (!cached) {
|
||||||
|
cache.put(newValue, newValue.comp().createRegion());
|
||||||
|
}
|
||||||
|
var r = cache.get(newValue);
|
||||||
|
struc.get().getChildren().clear();
|
||||||
|
struc.get().getChildren().add(r);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -154,35 +204,6 @@ public class BrowserSessionComp extends SimpleComp {
|
||||||
tabs.getHeaderHeight().subscribe(number -> {
|
tabs.getHeaderHeight().subscribe(number -> {
|
||||||
AnchorPane.setTopAnchor(struc.get(), number.doubleValue());
|
AnchorPane.setTopAnchor(struc.get(), number.doubleValue());
|
||||||
});
|
});
|
||||||
});
|
}); return pinnedStack;
|
||||||
|
|
||||||
var loadingStack = new AnchorComp(List.of(tabs, pinnedStack, loadingIndicator));
|
|
||||||
var splitPane = new LeftSplitPaneComp(vertical, loadingStack)
|
|
||||||
.withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth())
|
|
||||||
.withOnDividerChange(d -> {
|
|
||||||
AppLayoutModel.get().getSavedState().setBrowserConnectionsWidth(d);
|
|
||||||
leftSplit.set(d);
|
|
||||||
});
|
|
||||||
splitPane.apply(struc -> {
|
|
||||||
struc.getLeft().setMinWidth(200);
|
|
||||||
struc.getLeft().setMaxWidth(500);
|
|
||||||
struc.get().setPickOnBounds(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
splitPane.apply(struc -> {
|
|
||||||
struc.get().skinProperty().subscribe(newValue -> {
|
|
||||||
if (newValue != null) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
struc.get().getChildrenUnmodifiable().forEach(node -> {
|
|
||||||
node.setClip(null);
|
|
||||||
node.setPickOnBounds(false);
|
|
||||||
});
|
|
||||||
struc.get().lookupAll(".split-pane-divider").forEach(node -> node.setViewOrder(1));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
splitPane.styleClass("browser");
|
|
||||||
return splitPane.createRegion();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,7 @@ import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableMap;
|
import javafx.collections.ObservableMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class BrowserSessionModel extends BrowserAbstractSessionModel<BrowserSessionTab> {
|
public class BrowserSessionModel extends BrowserAbstractSessionModel<BrowserSessionTab> {
|
||||||
|
@ -79,6 +77,16 @@ public class BrowserSessionModel extends BrowserAbstractSessionModel<BrowserSess
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<BrowserSessionTab> getAllTabs() {
|
||||||
|
var set = new HashSet<BrowserSessionTab>();
|
||||||
|
set.addAll(sessionEntries);
|
||||||
|
set.addAll(splits.values());
|
||||||
|
if (globalPinnedTab.getValue() != null) {
|
||||||
|
set.add(globalPinnedTab.getValue());
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
public void splitTab(BrowserSessionTab tab, BrowserSessionTab split) {
|
public void splitTab(BrowserSessionTab tab, BrowserSessionTab split) {
|
||||||
if (splits.containsKey(tab)) {
|
if (splits.containsKey(tab)) {
|
||||||
return;
|
return;
|
||||||
|
@ -98,7 +106,6 @@ public class BrowserSessionModel extends BrowserAbstractSessionModel<BrowserSess
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void pinTab(BrowserSessionTab tab) {
|
public void pinTab(BrowserSessionTab tab) {
|
||||||
if (tab.equals(globalPinnedTab.getValue())) {
|
if (tab.equals(globalPinnedTab.getValue())) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -18,13 +18,11 @@ public abstract class BrowserSessionTab {
|
||||||
protected final BooleanProperty busy = new SimpleBooleanProperty();
|
protected final BooleanProperty busy = new SimpleBooleanProperty();
|
||||||
protected final BrowserAbstractSessionModel<?> browserModel;
|
protected final BrowserAbstractSessionModel<?> browserModel;
|
||||||
protected final String name;
|
protected final String name;
|
||||||
protected final String tooltip;
|
|
||||||
protected final Property<BrowserSessionTab> splitTab = new SimpleObjectProperty<>();
|
protected final Property<BrowserSessionTab> splitTab = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
public BrowserSessionTab(BrowserAbstractSessionModel<?> browserModel, String name, String tooltip) {
|
public BrowserSessionTab(BrowserAbstractSessionModel<?> browserModel, String name) {
|
||||||
this.browserModel = browserModel;
|
this.browserModel = browserModel;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tooltip = tooltip;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Comp<?> comp();
|
public abstract Comp<?> comp();
|
||||||
|
|
|
@ -426,28 +426,6 @@ public class BrowserSessionTabsComp extends SimpleComp {
|
||||||
});
|
});
|
||||||
tab.setContent(split);
|
tab.setContent(split);
|
||||||
|
|
||||||
// var lastSplitRegion = new AtomicReference<Region>();
|
|
||||||
// model.getGlobalPinnedTab().subscribe( (newValue) -> {
|
|
||||||
// PlatformThread.runLaterIfNeeded(() -> {
|
|
||||||
// if (newValue != null) {
|
|
||||||
// var r = newValue.comp().createRegion();
|
|
||||||
// split.getItems().add(r);
|
|
||||||
// lastSplitRegion.set(r);
|
|
||||||
// } else if (split.getItems().size() > 1) {
|
|
||||||
// split.getItems().removeLast();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// model.getSelectedEntry().addListener((observable, oldValue, newValue) -> {
|
|
||||||
// PlatformThread.runLaterIfNeeded(() -> {
|
|
||||||
// if (newValue != null && newValue.equals(model.getGlobalPinnedTab().getValue()) && split.getItems().size() > 1) {
|
|
||||||
// split.getItems().remove(lastSplitRegion.get());
|
|
||||||
// } else if (split.getItems().size() > 1 && !split.getItems().contains(lastSplitRegion.get())) {
|
|
||||||
// split.getItems().add(lastSplitRegion.get());
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
var id = UUID.randomUUID().toString();
|
var id = UUID.randomUUID().toString();
|
||||||
tab.setId(id);
|
tab.setId(id);
|
||||||
|
|
||||||
|
@ -471,7 +449,6 @@ public class BrowserSessionTabsComp extends SimpleComp {
|
||||||
if (color != null) {
|
if (color != null) {
|
||||||
c.getStyleClass().add(color.getId());
|
c.getStyleClass().add(color.getId());
|
||||||
}
|
}
|
||||||
new TooltipAugment<>(new SimpleStringProperty(tabModel.getTooltip()), null).augment(c);
|
|
||||||
c.addEventHandler(
|
c.addEventHandler(
|
||||||
DragEvent.DRAG_ENTERED,
|
DragEvent.DRAG_ENTERED,
|
||||||
mouseEvent -> Platform.runLater(
|
mouseEvent -> Platform.runLater(
|
||||||
|
|
|
@ -16,8 +16,7 @@ public abstract class BrowserStoreSessionTab<T extends DataStore> extends Browse
|
||||||
public BrowserStoreSessionTab(BrowserAbstractSessionModel<?> browserModel, DataStoreEntryRef<? extends T> entry) {
|
public BrowserStoreSessionTab(BrowserAbstractSessionModel<?> browserModel, DataStoreEntryRef<? extends T> entry) {
|
||||||
super(
|
super(
|
||||||
browserModel,
|
browserModel,
|
||||||
DataStorage.get().getStoreEntryDisplayName(entry.get()),
|
DataStorage.get().getStoreEntryDisplayName(entry.get()));
|
||||||
DataStorage.get().getStorePath(entry.getEntry()).toString());
|
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,18 +69,7 @@ public class StoreEntryListOverviewComp extends SimpleComp {
|
||||||
.getValue()
|
.getValue()
|
||||||
.getRoot()
|
.getRoot()
|
||||||
.equals(rootCategory);
|
.equals(rootCategory);
|
||||||
// Sadly the all binding does not update when the individual visibility of entries changes
|
return inRootCategory;
|
||||||
// But it is good enough.
|
|
||||||
var showProvider = true;
|
|
||||||
try {
|
|
||||||
showProvider = storeEntryWrapper.getEntry().getProvider() == null
|
|
||||||
|| storeEntryWrapper
|
|
||||||
.getEntry()
|
|
||||||
.getProvider()
|
|
||||||
.shouldShow(storeEntryWrapper);
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
return inRootCategory && showProvider;
|
|
||||||
},
|
},
|
||||||
StoreViewState.get().getActiveCategory());
|
StoreViewState.get().getActiveCategory());
|
||||||
var count = new CountComp<>(all.getList(), all.getList());
|
var count = new CountComp<>(all.getList(), all.getList());
|
||||||
|
|
|
@ -60,7 +60,11 @@ public class TerminalDockComp extends SimpleComp {
|
||||||
model.onClose();
|
model.onClose();
|
||||||
});
|
});
|
||||||
s.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
s.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
if (newValue) {
|
||||||
|
model.onFocusGain();
|
||||||
|
} else {
|
||||||
|
model.onFocusLost();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
stack.setOnMouseClicked(event -> {
|
stack.setOnMouseClicked(event -> {
|
||||||
model.clickView();
|
model.clickView();
|
||||||
|
|
|
@ -29,7 +29,9 @@ public class TerminalDockModel {
|
||||||
public synchronized void trackTerminal(TerminalViewInstance terminal) {
|
public synchronized void trackTerminal(TerminalViewInstance terminal) {
|
||||||
terminalInstances.add(terminal);
|
terminalInstances.add(terminal);
|
||||||
terminal.alwaysInFront();
|
terminal.alwaysInFront();
|
||||||
terminal.updatePosition(viewBounds);
|
if (viewBounds != null) {
|
||||||
|
terminal.updatePosition(viewBounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void closeTerminal(TerminalViewInstance terminal) {
|
public synchronized void closeTerminal(TerminalViewInstance terminal) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ public final class WindowsTerminalViewInstance extends TerminalViewInstance {
|
||||||
@Override
|
@Override
|
||||||
public void alwaysInFront() {
|
public void alwaysInFront() {
|
||||||
this.control.alwaysInFront();
|
this.control.alwaysInFront();
|
||||||
this.control.removeBorders();
|
// this.control.removeBorders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -13,6 +13,10 @@ public class BooleanScope implements AutoCloseable {
|
||||||
this.prop = prop;
|
this.prop = prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean get() {
|
||||||
|
return prop.get();
|
||||||
|
}
|
||||||
|
|
||||||
public static <E extends Throwable> void executeExclusive(BooleanProperty prop, FailableRunnable<E> r) throws E {
|
public static <E extends Throwable> void executeExclusive(BooleanProperty prop, FailableRunnable<E> r) throws E {
|
||||||
try (var ignored = new BooleanScope(prop).exclusive().start()) {
|
try (var ignored = new BooleanScope(prop).exclusive().start()) {
|
||||||
r.run();
|
r.run();
|
||||||
|
|
|
@ -99,12 +99,13 @@ public class DesktopShortcuts {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Path create(String executable, String args, String name) throws Exception {
|
public static Path create(String executable, String args, String name) throws Exception {
|
||||||
|
var compat = OsType.getLocal().makeFileSystemCompatible(name);
|
||||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||||
return createWindowsShortcut(executable, args, name);
|
return createWindowsShortcut(executable, args, compat);
|
||||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||||
return createLinuxShortcut(executable, args, name);
|
return createLinuxShortcut(executable, args, compat);
|
||||||
} else {
|
} else {
|
||||||
return createMacOSShortcut(executable, args, name);
|
return createMacOSShortcut(executable, args, compat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,13 @@ public class OpenTerminalAction implements LeafAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AppPrefs.get().enableTerminalDocking().get() && model.getBrowserModel() instanceof BrowserSessionModel sessionModel) {
|
if (AppPrefs.get().enableTerminalDocking().get() && model.getBrowserModel() instanceof BrowserSessionModel sessionModel) {
|
||||||
sessionModel.splitTab(model,new BrowserTerminalDockTabModel(sessionModel, model, model.getTerminalRequests()));
|
// Check if the right side is already occupied
|
||||||
|
var existingSplit = sessionModel.getSplits().get(model);
|
||||||
|
if (existingSplit != null && !(existingSplit instanceof BrowserTerminalDockTabModel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionModel.splitTab(model, new BrowserTerminalDockTabModel(sessionModel, model, model.getTerminalRequests()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue