mirror of
https://github.com/xpipe-io/xpipe.git
synced 2025-02-26 20:29:53 +00:00
Various fixes [stage]
This commit is contained in:
parent
a097ae7a41
commit
447ec12023
12 changed files with 73 additions and 63 deletions
|
@ -19,7 +19,6 @@ apply from: "$projectDir/gradle_scripts/richtextfx.gradle"
|
|||
apply from: "$rootDir/gradle/gradle_scripts/commons.gradle"
|
||||
apply from: "$rootDir/gradle/gradle_scripts/prettytime.gradle"
|
||||
apply from: "$projectDir/gradle_scripts/sentry.gradle"
|
||||
apply from: "$projectDir/gradle_scripts/fxtrayicon.gradle"
|
||||
apply from: "$rootDir/gradle/gradle_scripts/lombok.gradle"
|
||||
apply from: "$projectDir/gradle_scripts/github-api.gradle"
|
||||
apply from: "$projectDir/gradle_scripts/flexmark.gradle"
|
||||
|
@ -39,6 +38,7 @@ dependencies {
|
|||
compileOnly 'org.junit.jupiter:junit-jupiter-api:5.9.3'
|
||||
compileOnly 'org.junit.jupiter:junit-jupiter-params:5.9.3'
|
||||
|
||||
implementation 'com.dustinredmond.fxtrayicon:FXTrayIcon:4.0.1'
|
||||
implementation 'net.java.dev.jna:jna-jpms:5.13.0'
|
||||
implementation 'net.java.dev.jna:jna-platform-jpms:5.13.0'
|
||||
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.15.2"
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
dependencies {
|
||||
implementation files("$buildDir/generated-modules/FXTrayIcon-3.1.2.jar")
|
||||
}
|
||||
|
||||
addDependenciesModuleInfo {
|
||||
overwriteExistingFiles = true
|
||||
jdepsExtraArgs = ['-q']
|
||||
outputDirectory = file("$buildDir/generated-modules")
|
||||
modules {
|
||||
module {
|
||||
artifact 'com.dustinredmond.fxtrayicon:FXTrayIcon:3.1.2'
|
||||
moduleInfoSource = '''
|
||||
module com.dustinredmond.fxtrayicon {
|
||||
exports com.dustinredmond.fxtrayicon;
|
||||
exports com.dustinredmond.fxtrayicon.annotations;
|
||||
|
||||
requires transitive javafx.controls;
|
||||
requires transitive javafx.base;
|
||||
requires transitive java.desktop;
|
||||
}
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ import javafx.scene.control.skin.TableViewSkin;
|
|||
import javafx.scene.control.skin.VirtualFlow;
|
||||
import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
|
@ -127,6 +128,8 @@ final class BrowserFileListComp extends SimpleComp {
|
|||
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||
}
|
||||
|
||||
table.getSelectionModel().setCellSelectionEnabled(false);
|
||||
|
||||
table.getSelectionModel().getSelectedItems().addListener((ListChangeListener<? super BrowserEntry>) c -> {
|
||||
var toSelect = new ArrayList<>(c.getList());
|
||||
// Explicitly unselect synthetic entries since we can't use a custom selection model as that is bugged in
|
||||
|
@ -192,7 +195,7 @@ final class BrowserFileListComp extends SimpleComp {
|
|||
}
|
||||
|
||||
private void prepareTableEntries(TableView<BrowserEntry> table) {
|
||||
var emptyEntry = new BrowserFileListCompEntry(table, null, fileList);
|
||||
var emptyEntry = new BrowserFileListCompEntry(table, table, null, fileList);
|
||||
table.setOnMouseClicked(e -> {
|
||||
emptyEntry.onMouseClick(e);
|
||||
});
|
||||
|
@ -215,6 +218,14 @@ final class BrowserFileListComp extends SimpleComp {
|
|||
emptyEntry.onDragDrop(event);
|
||||
});
|
||||
|
||||
// Don't let the list view see this event
|
||||
// otherwise it unselects everything as it doesn't understand shift clicks
|
||||
table.addEventFilter(MouseEvent.MOUSE_CLICKED, t -> {
|
||||
if (t.getButton() == MouseButton.PRIMARY && t.isShiftDown() && t.getClickCount() == 1) {
|
||||
t.consume();
|
||||
}
|
||||
});
|
||||
|
||||
table.setRowFactory(param -> {
|
||||
TableRow<BrowserEntry> row = new TableRow<>();
|
||||
row.accessibleTextProperty()
|
||||
|
@ -257,7 +268,15 @@ final class BrowserFileListComp extends SimpleComp {
|
|||
})
|
||||
.augment(new SimpleCompStructure<>(row));
|
||||
var listEntry = Bindings.createObjectBinding(
|
||||
() -> new BrowserFileListCompEntry(row, row.getItem(), fileList), row.itemProperty());
|
||||
() -> new BrowserFileListCompEntry(table, row, row.getItem(), fileList), row.itemProperty());
|
||||
|
||||
// Don't let the list view see this event
|
||||
// otherwise it unselects everything as it doesn't understand shift clicks
|
||||
row.addEventFilter(MouseEvent.MOUSE_PRESSED, t -> {
|
||||
if (t.getButton() == MouseButton.PRIMARY && t.isShiftDown()) {
|
||||
listEntry.get().onMouseShiftClick(t);
|
||||
}
|
||||
});
|
||||
|
||||
row.itemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
row.pseudoClassStateChanged(DRAG, false);
|
||||
|
|
|
@ -9,6 +9,7 @@ import javafx.scene.input.*;
|
|||
import lombok.Getter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
|
@ -17,6 +18,7 @@ public class BrowserFileListCompEntry {
|
|||
|
||||
public static final Timer DROP_TIMER = new Timer("dnd", true);
|
||||
|
||||
private final TableView<BrowserEntry> tv;
|
||||
private final Node row;
|
||||
private final BrowserEntry item;
|
||||
private final BrowserFileListModel model;
|
||||
|
@ -24,46 +26,52 @@ public class BrowserFileListCompEntry {
|
|||
private Point2D lastOver = new Point2D(-1, -1);
|
||||
private TimerTask activeTask;
|
||||
|
||||
public BrowserFileListCompEntry(Node row, BrowserEntry item, BrowserFileListModel model) {
|
||||
public BrowserFileListCompEntry(TableView<BrowserEntry> tv, Node row, BrowserEntry item, BrowserFileListModel model) {
|
||||
this.tv = tv;
|
||||
this.row = row;
|
||||
this.item = item;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void onMouseClick(MouseEvent t) {
|
||||
t.consume();
|
||||
|
||||
if (item == null) {
|
||||
model.getSelection().clear();
|
||||
t.consume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.getClickCount() == 2 && t.getButton() == MouseButton.PRIMARY) {
|
||||
model.onDoubleClick(item);
|
||||
return;
|
||||
t.consume();
|
||||
}
|
||||
|
||||
t.consume();
|
||||
}
|
||||
|
||||
public void onMouseShiftClick(MouseEvent t) {
|
||||
if (isSynthetic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.getButton() == MouseButton.PRIMARY && t.isShiftDown()) {
|
||||
var tv = ((TableView<BrowserEntry>)
|
||||
row.getParent().getParent().getParent().getParent());
|
||||
var all = tv.getItems();
|
||||
var min = tv.getSelectionModel().getSelectedIndices().stream()
|
||||
.mapToInt(value -> value)
|
||||
.min()
|
||||
.orElse(1);
|
||||
var max = tv.getSelectionModel().getSelectedIndices().stream()
|
||||
.mapToInt(value -> value)
|
||||
.max()
|
||||
.orElse(all.size() - 1);
|
||||
var end = tv.getSelectionModel().getFocusedIndex();
|
||||
var start = end > min ? min : max;
|
||||
tv.getSelectionModel().selectRange(Math.min(start, end), Math.max(start, end) + 1);
|
||||
var all = tv.getItems();
|
||||
var index = item != null ? all.indexOf(item) : all.size() - 1;
|
||||
var min = Math.min(index, tv.getSelectionModel().getSelectedIndices().stream()
|
||||
.mapToInt(value -> value)
|
||||
.min()
|
||||
.orElse(1));
|
||||
var max = Math.max(index, tv.getSelectionModel().getSelectedIndices().stream()
|
||||
.mapToInt(value -> value)
|
||||
.max()
|
||||
.orElse(all.indexOf(item)));
|
||||
|
||||
var toSelect = new ArrayList<BrowserEntry>();
|
||||
for (int i = min; i <= max; i++) {
|
||||
if (!model.getSelection().contains(model.getShown().getValue().get(i))) {
|
||||
toSelect.add(model.getShown().getValue().get(i));
|
||||
}
|
||||
}
|
||||
model.getSelection().addAll(toSelect);
|
||||
t.consume();
|
||||
}
|
||||
|
||||
public boolean isSynthetic() {
|
||||
|
|
|
@ -73,7 +73,7 @@ public class BrowserStatusBarComp extends SimpleComp {
|
|||
}
|
||||
|
||||
private void simulateEmptyCell(Region r) {
|
||||
var emptyEntry = new BrowserFileListCompEntry(r, null, model.getFileList());
|
||||
var emptyEntry = new BrowserFileListCompEntry(null, r, null, model.getFileList());
|
||||
r.setOnMouseClicked(e -> {
|
||||
emptyEntry.onMouseClick(e);
|
||||
});
|
||||
|
|
|
@ -513,7 +513,6 @@ public class AppPrefs {
|
|||
|
||||
var categories = new ArrayList<>(List.of(
|
||||
Category.of("about", Group.of(about)),
|
||||
Category.of("troubleshoot", Group.of(troubleshoot)),
|
||||
Category.of(
|
||||
"system",
|
||||
Group.of(
|
||||
|
@ -586,7 +585,8 @@ public class AppPrefs {
|
|||
Setting.of(
|
||||
"developerShowHiddenProviders",
|
||||
developerShowHiddenProvidersField,
|
||||
developerShowHiddenProviders))));
|
||||
developerShowHiddenProviders)),
|
||||
Category.of("troubleshoot", Group.of(troubleshoot))));
|
||||
|
||||
categories.get(categories.size() - 1).setVisibilityProperty(VisibilityProperty.of(developerMode()));
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
AppFont.setSize(titleLabel, 2);
|
||||
// Set margin for all but first group titles to visually separate groups
|
||||
if (nextRow > 1) {
|
||||
GridPane.setMargin(titleLabel, new Insets(SPACING * 3, 0, SPACING, 0));
|
||||
GridPane.setMargin(titleLabel, new Insets(SPACING * 5, 0, SPACING, 0));
|
||||
} else {
|
||||
GridPane.setMargin(titleLabel, new Insets(SPACING, 0, SPACING, 0));
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
GridPane.setMargin(node, new Insets(SPACING, 0, 0, offset));
|
||||
|
||||
if (!((i == 0) && (nextRow > 0))) {
|
||||
GridPane.setMargin(c.getFieldLabel(), new Insets(SPACING * 3, 0, 0, offset));
|
||||
GridPane.setMargin(c.getFieldLabel(), new Insets(SPACING * 6, 0, 0, offset));
|
||||
} else {
|
||||
GridPane.setMargin(c.getFieldLabel(), new Insets(SPACING, 0, 0, offset));
|
||||
}
|
||||
|
|
|
@ -25,6 +25,10 @@ public interface ShellDialect {
|
|||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
default boolean isSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
CommandControl queryVersion(ShellControl shellControl);
|
||||
|
||||
CommandControl prepareTempDirectory(ShellControl shellControl, String directory);
|
||||
|
|
2
dist/changelogs/1.3.0.md
vendored
2
dist/changelogs/1.3.0.md
vendored
|
@ -2,3 +2,5 @@
|
|||
|
||||
- Completely rework connection management
|
||||
(Note that this change might remove some old connections that we're not compatible with the new system.)
|
||||
- Add shift-click selection to file browser
|
||||
- Many small miscellaneous fixes and improvements
|
||||
|
|
|
@ -5,9 +5,6 @@ import io.xpipe.app.browser.OpenFileSystemModel;
|
|||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -45,11 +42,6 @@ public class OpenDirectoryInNewTabAction implements LeafAction {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyCombination getShortcut() {
|
||||
return new KeyCodeCombination(KeyCode.ENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
return "Open in new tab";
|
||||
|
|
|
@ -4,6 +4,7 @@ import io.xpipe.app.browser.BrowserEntry;
|
|||
import io.xpipe.app.browser.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.action.LeafAction;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
|
@ -12,6 +13,8 @@ import java.util.List;
|
|||
|
||||
public class OpenNativeFileDetailsAction implements LeafAction {
|
||||
|
||||
private static ShellControl powershell;
|
||||
|
||||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) throws Exception {
|
||||
ShellControl sc = model.getFileSystem().getShell().get();
|
||||
|
@ -24,9 +27,14 @@ public class OpenNativeFileDetailsAction implements LeafAction {
|
|||
$shell = New-Object -ComObject Shell.Application; $shell.NameSpace('%s').ParseName('%s').InvokeVerb('Properties')
|
||||
""",
|
||||
FileNames.getParent(e), FileNames.getFileName(e));
|
||||
try (var sub = sc.enforcedDialect(ShellDialects.POWERSHELL).start()) {
|
||||
sub.command(content).notComplex().execute();
|
||||
|
||||
// The Windows shell invoke verb functionality behaves kinda weirdly and only shows the window as long as the parent process is running.
|
||||
// So let's keep one process running
|
||||
if (powershell == null) {
|
||||
powershell = new LocalStore().control().subShell(ShellDialects.POWERSHELL).start();
|
||||
}
|
||||
|
||||
powershell.command(content).notComplex().execute();
|
||||
}
|
||||
case OsType.Linux linux -> {
|
||||
var dbus = String.format(
|
||||
|
@ -62,7 +70,7 @@ public class OpenNativeFileDetailsAction implements LeafAction {
|
|||
@Override
|
||||
public boolean isApplicable(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
var sc = model.getFileSystem().getShell();
|
||||
return model.isLocal() && !sc.get().getOsType().equals(OsType.WINDOWS);
|
||||
return model.isLocal();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,4 +24,5 @@ dependencies {
|
|||
dep "org.openjfx:javafx-graphics:20.0.1:${platform}"
|
||||
dep "org.openjfx:javafx-media:20.0.1:${platform}"
|
||||
dep "org.openjfx:javafx-web:20.0.1:${platform}"
|
||||
dep "org.openjfx:javafx-swing:20.0.1:${platform}"
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue