Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8346607: IGV: Support drag-and-drop for opening graph files #23040

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -37,8 +37,18 @@
import com.sun.hotspot.igv.settings.Settings;
import com.sun.hotspot.igv.util.LookupHistory;
import com.sun.hotspot.igv.view.EditorTopComponent;
import com.sun.hotspot.igv.view.PlaceholderTopComponent;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;
Expand Down Expand Up @@ -92,6 +102,9 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM
private GraphNode[] selectedGraphs = new GraphNode[0];
private Path documentPath = null;

private final DropTargetListener fileDropListener = new FileDropListener();
private final PlaceholderTopComponent editorPlaceholder = new PlaceholderTopComponent(fileDropListener);

private OutlineTopComponent() {
initComponents();

Expand All @@ -100,6 +113,17 @@ private OutlineTopComponent() {
initListView();
initToolbar();
server.startServer();

showEditorPlaceholder();

WindowManager.getDefault().invokeWhenUIReady(() -> {
new DropTarget(WindowManager.getDefault().getMainWindow(), fileDropListener);
});
}

private void showEditorPlaceholder() {
editorPlaceholder.open();
editorPlaceholder.requestActive();
}

public static GraphDocument getDocument() {
Expand Down Expand Up @@ -236,6 +260,11 @@ private void documentChanged() {
saveAction.setEnabled(enableButton);
saveAsAction.setEnabled(enableButton);
removeAllAction.setEnabled(enableButton);
if (document.getElements().isEmpty()) {
showEditorPlaceholder();
} else {
editorPlaceholder.close();
}
}

@Override
Expand Down Expand Up @@ -372,15 +401,20 @@ public void openFile() {
JFileChooser fc = new JFileChooser(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT));
fc.setFileFilter(graphFileFilter);
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
clearWorkspace();
String path = fc.getSelectedFile().getAbsolutePath();
Settings.get().put(Settings.DIRECTORY, path);
setDocumentPath(path);
try {
loadGraphDocument(path, true);
} catch (IOException e) {
throw new RuntimeException(e);
}
handleOpen(fc.getSelectedFile());
}
}

private void handleOpen(File file) {
clearWorkspace();
editorPlaceholder.close();
String path = file.getAbsolutePath();
Settings.get().put(Settings.DIRECTORY, path);
setDocumentPath(path);
try {
loadGraphDocument(path, true);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

Expand Down Expand Up @@ -590,6 +624,65 @@ public void setState(String state) {
handle.finish();
}

private class FileDropListener implements DropTargetListener {
@Override
public void dragEnter(DropTargetDragEvent dtde) {
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
dtde.acceptDrag(DnDConstants.ACTION_COPY);
} else {
dtde.rejectDrag();
}
}

@Override
public void dragOver(DropTargetDragEvent dtde) {
dragEnter(dtde);
}

@Override
public void dropActionChanged(DropTargetDragEvent dtde) {}

@Override
public void dragExit(DropTargetEvent dte) {}

@Override
public void drop(DropTargetDropEvent dtde) {
try {
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
dtde.acceptDrop(DnDConstants.ACTION_COPY);

List<File> droppedFiles = (List<File>) dtde.getTransferable()
.getTransferData(DataFlavor.javaFileListFlavor);

if (droppedFiles.isEmpty()) return;
if (droppedFiles.size() > 1) {
JOptionPane.showMessageDialog(null,
"Please only drag and drop one file as only one file can be open at a time.",
"Multiple Files Dropped", JOptionPane.WARNING_MESSAGE);
return;
}

File file = droppedFiles.get(0);

if (file.getName().endsWith(".xml") || file.getName().endsWith(".igv")) {
handleOpen(file);
} else {
JOptionPane.showMessageDialog(null,
"Unsupported file type: " + file.getName(),
"Unsupported File", JOptionPane.WARNING_MESSAGE);
}

dtde.dropComplete(true);
} else {
dtde.rejectDrop();
}
} catch (HeadlessException | UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
dtde.dropComplete(false);
}
}
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.view;

import java.awt.BorderLayout;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetListener;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import org.openide.windows.TopComponent;

/**
* This TopComponent is displayed in the editor location if no graphs have been loaded
* and allows the user to easily drag and drop graph files to be opened.
*/
public class PlaceholderTopComponent extends TopComponent {
public PlaceholderTopComponent(DropTargetListener fileDropListener) {
setLayout(new BorderLayout());
JPanel container = new JPanel(new BorderLayout());
container.add(new JLabel("Drop file here to open", SwingConstants.CENTER), BorderLayout.CENTER);
container.setDropTarget(new DropTarget(container, fileDropListener));
add(container, BorderLayout.CENTER);
setName("Welcome");
}
}