Skip to content

Commit eb831e2

Browse files
committed
Fix cell mouse events handling
1 parent a3241c5 commit eb831e2

File tree

2 files changed

+106
-79
lines changed

2 files changed

+106
-79
lines changed

src/main/java/sh/adelessfox/psarc/AppWindow.java

Lines changed: 75 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
import javafx.scene.control.Button;
1414
import javafx.scene.control.MenuItem;
1515
import javafx.scene.image.ImageView;
16-
import javafx.scene.input.*;
16+
import javafx.scene.input.DataFormat;
17+
import javafx.scene.input.Dragboard;
18+
import javafx.scene.input.KeyCombination;
19+
import javafx.scene.input.TransferMode;
1720
import javafx.scene.layout.BorderPane;
1821
import javafx.scene.paint.Color;
1922
import javafx.stage.DirectoryChooser;
@@ -22,10 +25,7 @@
2225
import javafx.stage.StageStyle;
2326
import org.slf4j.Logger;
2427
import org.slf4j.LoggerFactory;
25-
import sh.adelessfox.psarc.archive.Archive;
26-
import sh.adelessfox.psarc.archive.Asset;
27-
import sh.adelessfox.psarc.archive.AssetId;
28-
import sh.adelessfox.psarc.archive.PsarcArchive;
28+
import sh.adelessfox.psarc.archive.*;
2929
import sh.adelessfox.psarc.settings.Settings;
3030
import sh.adelessfox.psarc.ui.StatusBar;
3131
import sh.adelessfox.psarc.ui.StructuredTreeItem;
@@ -272,28 +272,6 @@ private <K extends AssetId, V extends Asset<K>> TreeTableView<ArchiveStructure<V
272272
}
273273
});
274274

275-
view.setOnDragDetected(event -> {
276-
var item = view.getSelectionModel().getSelectedItem();
277-
if (!(item.getValue() instanceof ArchiveStructure.File<V> file)) {
278-
return;
279-
}
280-
281-
File result;
282-
283-
@SuppressWarnings("unchecked")
284-
Archive<K, V> archive = (Archive<K, V>) this.archive.get();
285-
286-
try {
287-
result = extractToTemporaryFile(archive, file.asset).toFile();
288-
} catch (IOException e) {
289-
throw new UncheckedIOException(e);
290-
}
291-
292-
Dragboard dragboard = view.startDragAndDrop(TransferMode.MOVE);
293-
dragboard.setContent(Map.of(DataFormat.FILES, List.of(result)));
294-
event.consume();
295-
});
296-
297275
view.setOnDragOver(event -> {
298276
var dragboard = event.getDragboard();
299277
if (dragboard.hasFiles() && dragboard.getFiles().size() == 1) {
@@ -313,66 +291,45 @@ private <K extends AssetId, V extends Asset<K>> TreeTableView<ArchiveStructure<V
313291
event.consume();
314292
});
315293

316-
view.setOnMouseClicked(event -> {
317-
if (event.getButton() != MouseButton.PRIMARY || event.getClickCount() % 2 != 0) {
318-
return;
319-
}
320-
321-
// TODO: Fix double-click on the expander triggering the action
322-
var item = view.getSelectionModel().getSelectedItem();
323-
if (!(item.getValue() instanceof ArchiveStructure.File<V> file)) {
324-
return;
325-
}
326-
327-
@SuppressWarnings("unchecked")
328-
Archive<K, V> archive = (Archive<K, V>) this.archive.get();
329-
330-
try {
331-
Desktop.getDesktop().open(extractToTemporaryFile(archive, file.asset).toFile());
332-
} catch (IOException e) {
333-
throw new UncheckedIOException(e);
334-
}
335-
});
336-
337294
return view;
338295
}
339296

340-
private static <K extends AssetId, V extends Asset<K>> Path extractToTemporaryFile(Archive<K, V> archive, V asset) throws IOException {
341-
var id = asset.id();
342-
var root = Path.of(System.getProperty("java.io.tmpdir"), "psarc-dnd");
343-
var path = root.resolve(id.fileName());
344-
345-
log.debug("Creating a temporary file {}", path);
346-
347-
if (Files.notExists(root)) {
348-
Files.createDirectory(root);
349-
}
350-
351-
try (var channel = Files.newByteChannel(path, WRITE, CREATE, TRUNCATE_EXISTING)) {
352-
channel.write(archive.read(id));
353-
}
354-
355-
return path;
356-
}
357-
358-
private static <T extends Asset<?>> List<TreeTableColumn<ArchiveStructure<T>, ?>> buildTreeTableColumns() {
297+
private <T extends Asset<?>> List<TreeTableColumn<ArchiveStructure<T>, ?>> buildTreeTableColumns() {
359298
var nameColumn = new TreeTableColumn<ArchiveStructure<T>, ArchiveStructure<T>>("Name");
360299
nameColumn.setReorderable(false);
361300
nameColumn.setSortable(false);
362301
nameColumn.setCellValueFactory(features -> features.getValue().valueProperty());
363-
nameColumn.setCellFactory(_ -> new TreeTableCell<>() {
364-
@Override
365-
protected void updateItem(ArchiveStructure<T> item, boolean empty) {
366-
super.updateItem(item, empty);
367-
368-
if (empty) {
369-
setText(null);
370-
setGraphic(null);
371-
} else {
372-
setText(item.name);
373-
setGraphic(Fugue.getImageView(item instanceof ArchiveStructure.File ? "document" : "folder"));
302+
nameColumn.setCellFactory(_ -> {
303+
var cell = new TreeTableCell<ArchiveStructure<T>, ArchiveStructure<T>>() {
304+
@Override
305+
protected void updateItem(ArchiveStructure<T> item, boolean empty) {
306+
super.updateItem(item, empty);
307+
308+
if (empty) {
309+
setText(null);
310+
setGraphic(null);
311+
} else {
312+
setText(item.name);
313+
setGraphic(Fugue.getImageView(item instanceof ArchiveStructure.File ? "document" : "folder"));
314+
}
374315
}
375-
}
316+
};
317+
cell.setOnMouseClicked(event -> {
318+
if (!FxUtils.isPrimaryDoubleClick(event) || FxUtils.isDisclosureNode(cell, event)) {
319+
return;
320+
}
321+
if (cell.getItem() instanceof ArchiveStructure.File<?> file) {
322+
openInExternalApplication((PsarcAsset) file.asset);
323+
event.consume();
324+
}
325+
});
326+
cell.setOnDragDetected(event -> {
327+
if (cell.getItem() instanceof ArchiveStructure.File<?> file) {
328+
startDragAndDrop(cell.getTreeTableView(), (PsarcAsset) file.asset);
329+
event.consume();
330+
}
331+
});
332+
return cell;
376333
});
377334

378335
var sizeColumn = new TreeTableColumn<ArchiveStructure<T>, ArchiveStructure<T>>("Size");
@@ -396,4 +353,43 @@ protected void updateItem(ArchiveStructure<T> item, boolean empty) {
396353

397354
return List.of(nameColumn, sizeColumn);
398355
}
356+
357+
private void startDragAndDrop(TreeTableView<?> view, PsarcAsset asset) {
358+
File result;
359+
360+
try {
361+
result = extractToTemporaryFile(archive.get(), asset).toFile();
362+
} catch (IOException e) {
363+
throw new UncheckedIOException(e);
364+
}
365+
366+
Dragboard dragboard = view.startDragAndDrop(TransferMode.MOVE);
367+
dragboard.setContent(Map.of(DataFormat.FILES, List.of(result)));
368+
}
369+
370+
private void openInExternalApplication(PsarcAsset asset) {
371+
try {
372+
Desktop.getDesktop().open(extractToTemporaryFile(archive.get(), asset).toFile());
373+
} catch (IOException e) {
374+
throw new UncheckedIOException(e);
375+
}
376+
}
377+
378+
private static <K extends AssetId, V extends Asset<K>> Path extractToTemporaryFile(Archive<K, V> archive, V asset) throws IOException {
379+
var id = asset.id();
380+
var root = Path.of(System.getProperty("java.io.tmpdir"), "psarc-dnd");
381+
var path = root.resolve(id.fileName());
382+
383+
log.debug("Creating a temporary file {}", path);
384+
385+
if (Files.notExists(root)) {
386+
Files.createDirectory(root);
387+
}
388+
389+
try (var channel = Files.newByteChannel(path, WRITE, CREATE, TRUNCATE_EXISTING)) {
390+
channel.write(archive.read(id));
391+
}
392+
393+
return path;
394+
}
399395
}

src/main/java/sh/adelessfox/psarc/util/FxUtils.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
import javafx.application.Application;
55
import javafx.application.Platform;
66
import javafx.scene.Scene;
7+
import javafx.scene.control.TableColumnBase;
8+
import javafx.scene.control.TreeTableCell;
79
import javafx.scene.input.KeyCombination;
10+
import javafx.scene.input.MouseButton;
11+
import javafx.scene.input.MouseEvent;
812
import javafx.stage.Stage;
913

1014
import java.net.URI;
@@ -37,4 +41,31 @@ public static void installStylesheetHotReload(Scene scene, String stylesheet) {
3741
return null;
3842
});
3943
}
44+
45+
public static boolean isPrimaryDoubleClick(MouseEvent event) {
46+
return event.getButton() == MouseButton.PRIMARY && event.getClickCount() % 2 == 0;
47+
}
48+
49+
public static <S, T> boolean isDisclosureNode(TreeTableCell<S, T> cell, MouseEvent event) {
50+
var treeTableView = cell.getTreeTableView();
51+
var treeColumn = treeTableView.getTreeColumn() == null ? treeTableView.getVisibleLeafColumn(0) : treeTableView.getTreeColumn();
52+
var column = cell.getTableColumn();
53+
54+
if (column != treeColumn) {
55+
return false;
56+
}
57+
58+
var disclosureNode = cell.getTableRow().getDisclosureNode();
59+
if (disclosureNode != null && disclosureNode.isVisible()) {
60+
double endX = disclosureNode.getBoundsInParent().getMaxX();
61+
double startX = treeTableView.getVisibleLeafColumns().stream()
62+
.takeWhile(tc -> tc != treeColumn)
63+
.mapToDouble(TableColumnBase::getWidth)
64+
.sum();
65+
66+
return event.getX() < endX - startX;
67+
}
68+
69+
return false;
70+
}
4071
}

0 commit comments

Comments
 (0)