1313import javafx .scene .control .Button ;
1414import javafx .scene .control .MenuItem ;
1515import 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 ;
1720import javafx .scene .layout .BorderPane ;
1821import javafx .scene .paint .Color ;
1922import javafx .stage .DirectoryChooser ;
2225import javafx .stage .StageStyle ;
2326import org .slf4j .Logger ;
2427import 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 .*;
2929import sh .adelessfox .psarc .settings .Settings ;
3030import sh .adelessfox .psarc .ui .StatusBar ;
3131import 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}
0 commit comments