Various fixes [stage]

This commit is contained in:
crschnick 2023-07-05 04:17:29 +00:00
parent a097ae7a41
commit 447ec12023
12 changed files with 73 additions and 63 deletions

View file

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

View file

@ -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;
}
'''
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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