8324950: IGV: save the state to a file

Reviewed-by: rcastanedalo, chagedorn
This commit is contained in:
Tobias Holenstein 2024-04-18 12:53:47 +00:00
parent 571e6bc3f7
commit ec180d4782
29 changed files with 1116 additions and 894 deletions

View File

@ -88,6 +88,11 @@
<artifactId>org-openide-util-lookup</artifactId>
<version>${netbeans.version}</version>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-modules</artifactId>
<version>${netbeans.version}</version>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-util-ui</artifactId>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -28,21 +28,32 @@ import com.sun.hotspot.igv.coordinator.actions.*;
import com.sun.hotspot.igv.data.ChangedListener;
import com.sun.hotspot.igv.data.GraphDocument;
import com.sun.hotspot.igv.data.InputGraph;
import com.sun.hotspot.igv.data.services.GroupCallback;
import com.sun.hotspot.igv.data.serialization.ParseMonitor;
import com.sun.hotspot.igv.data.serialization.Parser;
import com.sun.hotspot.igv.data.serialization.Printer;
import com.sun.hotspot.igv.data.serialization.Printer.GraphContext;
import com.sun.hotspot.igv.data.services.GraphViewer;
import com.sun.hotspot.igv.data.services.InputGraphProvider;
import com.sun.hotspot.igv.settings.Settings;
import com.sun.hotspot.igv.util.LookupHistory;
import com.sun.hotspot.igv.view.EditorTopComponent;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Set;
import javax.swing.UIManager;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.filechooser.FileFilter;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.ErrorManager;
import org.openide.actions.GarbageCollectAction;
import org.openide.awt.Toolbar;
import org.openide.awt.ToolbarPool;
import org.openide.explorer.ExplorerManager;
@ -50,7 +61,9 @@ import org.openide.explorer.ExplorerUtils;
import org.openide.explorer.view.BeanTreeView;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
@ -60,97 +73,42 @@ import org.openide.windows.WindowManager;
*/
public final class OutlineTopComponent extends TopComponent implements ExplorerManager.Provider, ChangedListener<InputGraphProvider> {
public static OutlineTopComponent instance;
public static final String PREFERRED_ID = "OutlineTopComponent";
private static final GraphDocument document = new GraphDocument();
private static final int WORK_UNITS = 10000;
private static final FileFilter xmlFileFilter = new FileFilter() {
@Override
public boolean accept(File f) {
return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory();
}
@Override
public String getDescription() {
return "Graph files (*.xml)";
}
};
private static final Server server = new Server(document, OutlineTopComponent::loadContext);
public static OutlineTopComponent instance;
private final Set<FolderNode> selectedFolders = new HashSet<>();
private ExplorerManager manager;
private final GraphDocument document;
private FolderNode root;
private SaveAllAction saveAllAction;
private SaveAction saveAction;
private SaveAsAction saveAsAction;
private RemoveAllAction removeAllAction;
private GraphNode[] selectedGraphs = new GraphNode[0];
private final Set<FolderNode> selectedFolders = new HashSet<>();
private Path documentPath = null;
private OutlineTopComponent() {
initComponents();
setName(NbBundle.getMessage(OutlineTopComponent.class, "CTL_OutlineTopComponent"));
setToolTipText(NbBundle.getMessage(OutlineTopComponent.class, "HINT_OutlineTopComponent"));
document = new GraphDocument();
initListView();
initToolbar();
initReceivers();
server.startServer();
}
private void initListView() {
manager = new ExplorerManager();
root = new FolderNode(document);
manager.setRootContext(root);
((BeanTreeView) this.treeView).setRootVisible(false);
associateLookup(ExplorerUtils.createLookup(manager, getActionMap()));
}
private void initToolbar() {
Toolbar toolbar = new Toolbar();
toolbar.setBorder((Border) UIManager.get("Nb.Editor.Toolbar.border")); //NOI18N
toolbar.setMinimumSize(new Dimension(0,0)); // MacOS BUG with ToolbarWithOverflow
this.add(toolbar, BorderLayout.NORTH);
toolbar.add(ImportAction.get(ImportAction.class));
toolbar.add(SaveAsAction.get(SaveAsAction.class).createContextAwareInstance(this.getLookup()));
saveAllAction = SaveAllAction.get(SaveAllAction.class);
saveAllAction.setEnabled(false);
toolbar.add(saveAllAction);
toolbar.add(RemoveAction.get(RemoveAction.class).createContextAwareInstance(this.getLookup()));
removeAllAction = RemoveAllAction.get(RemoveAllAction.class);
removeAllAction.setEnabled(false);
toolbar.add(removeAllAction);
toolbar.add(GarbageCollectAction.get(GarbageCollectAction.class).getToolbarPresenter());
for (Toolbar tb : ToolbarPool.getDefault().getToolbars()) {
tb.setVisible(false);
}
document.getChangedEvent().addListener(g -> documentChanged());
}
private void documentChanged() {
boolean enableButton = !document.getElements().isEmpty();
saveAllAction.setEnabled(enableButton);
removeAllAction.setEnabled(enableButton);
}
private void initReceivers() {
final GroupCallback callback = g -> {
synchronized(OutlineTopComponent.this) {
g.setParent(getDocument());
getDocument().addElement(g);
}
};
new Server(callback);
}
public void clear() {
document.clear();
FolderNode.clearGraphNodeMap();
root = new FolderNode(document);
manager.setRootContext(root);
}
@Override
public ExplorerManager getExplorerManager() {
return manager;
}
public GraphDocument getDocument() {
public static GraphDocument getDocument() {
return document;
}
@ -159,7 +117,7 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM
* i.e. deserialization routines; otherwise you could get a non-deserialized instance.
* To obtain the singleton instance, use {@link #findInstance()}.
*/
public static synchronized OutlineTopComponent getDefault() {
private static synchronized OutlineTopComponent getDefault() {
if (instance == null) {
instance = new OutlineTopComponent();
}
@ -182,6 +140,97 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM
return getDefault();
}
/**
* Stores the provided graph document to the designated file path with associated contexts.
*/
private static void saveGraphDocument(GraphDocument doc, String path) throws IOException {
List<GraphContext> saveContexts = new ArrayList<>();
WindowManager manager = WindowManager.getDefault();
for (Mode mode : manager.getModes()) {
List<TopComponent> compList = new ArrayList<>(Arrays.asList(manager.getOpenedTopComponents(mode)));
for (TopComponent comp : compList) {
if (comp instanceof EditorTopComponent etc) {
InputGraph graph = etc.getModel().getGraph();
if (graph.isDiffGraph() && graph.getFirstGraph().getGroup() != graph.getSecondGraph().getGroup()) {
// don't save diff graphs comparing graphs from different groups
continue;
}
GraphContext graphContext = getGraphContext(etc);
saveContexts.add(graphContext);
}
}
}
try (Writer writer = new OutputStreamWriter(new FileOutputStream(path))) {
Printer.exportGraphDocument(writer, doc, saveContexts);
}
}
private static GraphContext getGraphContext(EditorTopComponent etc) {
InputGraph openedGraph = etc.getModel().getFirstGraph();
int posDiff = etc.getModel().getSecondPosition() - etc.getModel().getFirstPosition();
if (etc.getModel().getHiddenNodes().isEmpty()) {
return new GraphContext(openedGraph, new AtomicInteger(posDiff), new HashSet<>(), new AtomicBoolean(true));
} else {
Set<Integer> visibleNodes = new HashSet<>(etc.getModel().getVisibleNodes());
return new GraphContext(openedGraph, new AtomicInteger(posDiff), visibleNodes, new AtomicBoolean(false));
}
}
private void initListView() {
setDocumentPath(null);
FolderNode.clearGraphNodeMap();
document.clear();
root = new FolderNode(document);
manager = new ExplorerManager();
manager.setRootContext(root);
((BeanTreeView) this.treeView).setRootVisible(false);
associateLookup(ExplorerUtils.createLookup(manager, getActionMap()));
}
private void initToolbar() {
Toolbar toolbar = new Toolbar();
toolbar.setBorder((Border) UIManager.get("Nb.Editor.Toolbar.border")); //NOI18N
toolbar.setMinimumSize(new Dimension(0, 0)); // MacOS BUG with ToolbarWithOverflow
this.add(toolbar, BorderLayout.NORTH);
toolbar.add(OpenAction.get(OpenAction.class));
toolbar.add(ImportAction.get(ImportAction.class));
toolbar.addSeparator();
saveAction = SaveAction.get(SaveAction.class);
saveAction.setEnabled(false);
toolbar.add(saveAction);
saveAsAction = SaveAsAction.get(SaveAsAction.class);
saveAsAction.setEnabled(false);
toolbar.add(saveAsAction);
toolbar.addSeparator();
toolbar.add(RemoveAction.get(RemoveAction.class).createContextAwareInstance(this.getLookup()));
removeAllAction = RemoveAllAction.get(RemoveAllAction.class);
removeAllAction.setEnabled(false);
toolbar.add(removeAllAction);
for (Toolbar tb : ToolbarPool.getDefault().getToolbars()) {
tb.setVisible(false);
}
document.getChangedEvent().addListener(g -> documentChanged());
}
private void documentChanged() {
boolean enableButton = !document.getElements().isEmpty();
saveAction.setEnabled(enableButton);
saveAsAction.setEnabled(enableButton);
removeAllAction.setEnabled(enableButton);
}
@Override
public ExplorerManager getExplorerManager() {
return manager;
}
@Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_ALWAYS;
@ -236,15 +285,12 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM
InputGraph graph = lastProvider.getGraph();
if (graph != null) {
if (graph.isDiffGraph()) {
EditorTopComponent editor = EditorTopComponent.getActive();
if (editor != null) {
InputGraph firstGraph = editor.getModel().getFirstGraph();
GraphNode firstNode = FolderNode.getGraphNode(firstGraph);
InputGraph secondGraph = editor.getModel().getSecondGraph();
GraphNode secondNode = FolderNode.getGraphNode(secondGraph);
if (firstNode != null && secondNode != null) {
selectedGraphs = new GraphNode[]{firstNode, secondNode};
}
InputGraph firstGraph = graph.getFirstGraph();
GraphNode firstNode = FolderNode.getGraphNode(firstGraph);
InputGraph secondGraph = graph.getSecondGraph();
GraphNode secondNode = FolderNode.getGraphNode(secondGraph);
if (firstNode != null && secondNode != null) {
selectedGraphs = new GraphNode[]{firstNode, secondNode};
}
} else {
GraphNode graphNode = FolderNode.getGraphNode(graph);
@ -271,15 +317,229 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM
}
@Override
public void readExternal(ObjectInput objectInput) throws IOException, ClassNotFoundException {
// Not called when user starts application for the first time
super.readExternal(objectInput);
((BeanTreeView) this.treeView).setRootVisible(false);
public boolean canClose() {
SwingUtilities.invokeLater(() -> {
clearWorkspace();
open(); // Reopen the OutlineTopComponent
requestActive();
});
return true;
}
@Override
public void writeExternal(ObjectOutput objectOutput) throws IOException {
super.writeExternal(objectOutput);
private void setDocumentPath(String path) {
if (path != null) {
documentPath = Paths.get(path);
setHtmlDisplayName("<html><b>" + documentPath.getFileName().toString() + "</b></html>");
setToolTipText("File: " + path);
} else {
documentPath = null;
setHtmlDisplayName("<html><i>untitled</i></html>");
setToolTipText("No file");
}
}
/**
* Clears the workspace by resetting the document path, clearing the document, and resetting the folder structure.
* After clearing the workspace, it will be ready for new documents.
*/
public void clearWorkspace() {
setDocumentPath(null);
document.clear();
FolderNode.clearGraphNodeMap();
root = new FolderNode(document);
manager.setRootContext(root);
EditorTopComponent.closeAllInstances();
}
/**
* Opens a file dialog to select and load a graph document.
* Clears the workspace and adds the loaded document to the workspace.
**/
public void openFile() {
JFileChooser fc = new JFileChooser(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT));
fc.setFileFilter(xmlFileFilter);
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);
}
}
}
private boolean overwriteDialog(String filename) {
JFrame frame = new JFrame();
String message = "Do you want to overwrite " + filename + "?";
int result = JOptionPane.showConfirmDialog(frame, message, "Confirm Overwrite", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
frame.dispose();
return result == JOptionPane.YES_OPTION;
}
/**
* Saves the current graph document.
* If the document has no location, let the user specify the file location.
*/
public void save() {
if (documentPath == null) {
saveAs();
return;
}
String filePath = documentPath.toAbsolutePath().toString();
if (Files.exists(Paths.get(filePath)) && overwriteDialog(documentPath.getFileName().toString())) {
try {
saveGraphDocument(getDocument(), filePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
saveAs();
}
}
public void saveAs() {
JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Save As...");
fc.setFileFilter(xmlFileFilter);
fc.setCurrentDirectory(new File(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT)));
if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getAbsolutePath();
// Ask if the user wants to overwrite the file if it already exists
if (Files.exists(Paths.get(path)) && !overwriteDialog(fc.getSelectedFile().getName())) {
return; // user does not want to overwrite
}
Settings.get().put(Settings.DIRECTORY, path);
setDocumentPath(path);
try {
saveGraphDocument(getDocument(), path);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* Imports graph documents from one or more XML files.
* Displays a file chooser dialog to select one or multiple XML files for import.
* Each selected file is added to the workspace.
**/
public void importFromXML() {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(xmlFileFilter);
fc.setCurrentDirectory(new File(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT)));
fc.setMultiSelectionEnabled(true);
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
for (final File file : fc.getSelectedFiles()) {
String path = file.getAbsolutePath();
Settings.get().put(Settings.DIRECTORY, path);
try {
loadGraphDocument(path, false);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
/**
* Loads and opens the given graph context (opened graphs and visible nodes).
*/
private static void loadContext(GraphContext context) {
final GraphViewer viewer = Lookup.getDefault().lookup(GraphViewer.class);
if (viewer != null) {
final int difference = context.posDiff().get();
final InputGraph firstGraph = context.inputGraph();
final Set<Integer> visibleNodes = context.visibleNodes();
final boolean showAll = context.showAll().get();
SwingUtilities.invokeLater(() -> {
InputGraph openedGraph = viewer.view(firstGraph, true);
if (openedGraph != null) {
EditorTopComponent etc = EditorTopComponent.findEditorForGraph(firstGraph);
if (etc != null) {
if (showAll) {
etc.getModel().setHiddenNodes(new HashSet<>());
} else {
etc.getModel().showOnly(visibleNodes);
}
int firstGraphIdx = firstGraph.getIndex();
if (difference > 0) {
etc.getModel().setPositions(firstGraphIdx, firstGraphIdx + difference);
} else if (difference < 0) {
etc.getModel().setPositions(firstGraphIdx + difference, firstGraphIdx);
}
}
}
});
}
}
/**
* Loads a graph document from the given file path, updating progress via a ProgressHandle.
* Parse the XML file, add the parsed document to the workspace, and load associated contexts if specified.
*/
private void loadGraphDocument(String path, boolean loadContext) throws IOException {
if (Files.notExists(Path.of(path))) {
return;
}
File file = new File(path);
final FileChannel channel;
final long start;
try {
channel = FileChannel.open(file.toPath(), StandardOpenOption.READ);
start = channel.size();
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
return;
}
final ProgressHandle handle = ProgressHandleFactory.createHandle("Opening file " + file.getName());
handle.start(WORK_UNITS);
ParseMonitor monitor = new ParseMonitor() {
@Override
public void updateProgress() {
try {
int prog = (int) (WORK_UNITS * (double) channel.position() / (double) start);
handle.progress(prog);
} catch (IOException ignored) {
}
}
@Override
public void setState(String state) {
updateProgress();
handle.progress(state);
}
};
try {
if (file.getName().endsWith(".xml")) {
ArrayList<GraphContext> contexts = new ArrayList<>();
final Parser parser = new Parser(channel, monitor, document, loadContext ? contexts::add : null);
parser.parse();
SwingUtilities.invokeLater(() -> {
for (Node child : manager.getRootContext().getChildren().getNodes(true)) {
// Nodes are lazily created. By expanding and collapsing they are all initialized
((BeanTreeView) this.treeView).expandNode(child);
((BeanTreeView) this.treeView).collapseNode(child);
}
requestActive();
});
for (GraphContext ctx : contexts) {
loadContext(ctx);
}
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
handle.finish();
}
/** This method is called from within the constructor to

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -25,24 +25,10 @@
package com.sun.hotspot.igv.coordinator.actions;
import com.sun.hotspot.igv.coordinator.OutlineTopComponent;
import com.sun.hotspot.igv.data.GraphDocument;
import com.sun.hotspot.igv.data.serialization.GraphParser;
import com.sun.hotspot.igv.data.serialization.ParseMonitor;
import com.sun.hotspot.igv.data.serialization.Parser;
import com.sun.hotspot.igv.settings.Settings;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.*;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
/**
@ -51,89 +37,15 @@ import org.openide.util.actions.CallableSystemAction;
*/
public final class ImportAction extends CallableSystemAction {
private static final int WORKUNITS = 10000;
public static FileFilter getFileFilter() {
return new FileFilter() {
@Override
public boolean accept(File f) {
return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory();
}
@Override
public String getDescription() {
return "Graph files (*.xml)";
}
};
public ImportAction() {
putValue(Action.SHORT_DESCRIPTION, "Import from XML...");
putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon(iconResource(), true));
}
@Override
public void performAction() {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(ImportAction.getFileFilter());
fc.setCurrentDirectory(new File(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT)));
fc.setMultiSelectionEnabled(true);
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
for (final File file : fc.getSelectedFiles()) {
File dir = file;
if (!dir.isDirectory()) {
dir = dir.getParentFile();
}
Settings.get().put(Settings.DIRECTORY, dir.getAbsolutePath());
try {
final FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.READ);
final ProgressHandle handle = ProgressHandleFactory.createHandle("Opening file " + file.getName());
handle.start(WORKUNITS);
final long startTime = System.currentTimeMillis();
final long start = channel.size();
ParseMonitor monitor = new ParseMonitor() {
@Override
public void updateProgress() {
try {
int prog = (int) (WORKUNITS * (double) channel.position() / (double) start);
handle.progress(prog);
} catch (IOException ignored) {}
}
@Override
public void setState(String state) {
updateProgress();
handle.progress(state);
}
};
final GraphParser parser;
final OutlineTopComponent component = OutlineTopComponent.findInstance();
if (file.getName().endsWith(".xml")) {
parser = new Parser(channel, monitor, null);
} else {
parser = null;
}
RequestProcessor.getDefault().post(new Runnable() {
@Override
public void run() {
try {
final GraphDocument document = parser.parse();
if (document != null) {
SwingUtilities.invokeLater(() -> {
component.requestActive();
component.getDocument().addGraphDocument(document);
});
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
handle.finish();
long stop = System.currentTimeMillis();
Logger.getLogger(getClass().getName()).log(Level.INFO, "Loaded in " + file + " in " + ((stop - startTime) / 1000.0) + " seconds");
}
});
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
OutlineTopComponent.findInstance().importFromXML();
}
@Override
@ -141,12 +53,6 @@ public final class ImportAction extends CallableSystemAction {
return NbBundle.getMessage(ImportAction.class, "CTL_ImportAction");
}
public ImportAction() {
putValue(Action.SHORT_DESCRIPTION, "Open");
// D is the Control key on most platforms, the Command (meta) key on Macintosh
putValue(Action.ACCELERATOR_KEY, Utilities.stringToKey("D-O"));
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2024, 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.coordinator.actions;
import com.sun.hotspot.igv.coordinator.OutlineTopComponent;
import javax.swing.Action;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.actions.CallableSystemAction;
public final class OpenAction extends CallableSystemAction {
public OpenAction() {
putValue(Action.SHORT_DESCRIPTION, "Open...");
// D is the Control key on most platforms, the Command (meta) key on Macintosh
putValue(Action.ACCELERATOR_KEY, Utilities.stringToKey("D-O"));
putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon(iconResource(), true));
}
@Override
public void performAction() {
OutlineTopComponent.findInstance().openFile();
}
@Override
public String getName() {
return NbBundle.getMessage(OpenAction.class, "CTL_OpenAction");
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
@Override
protected boolean asynchronous() {
return false;
}
@Override
protected String iconResource() {
return "com/sun/hotspot/igv/coordinator/images/open.png";
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -28,6 +28,7 @@ import com.sun.hotspot.igv.coordinator.FolderNode;
import javax.swing.Action;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.actions.NodeAction;
@ -37,6 +38,11 @@ import org.openide.util.actions.NodeAction;
*/
public final class RemoveAction extends NodeAction {
public RemoveAction() {
putValue(Action.SHORT_DESCRIPTION, getName());
putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon(iconResource(), true));
}
@Override
protected void performAction(Node[] activatedNodes) {
for (Node n : activatedNodes) {
@ -47,10 +53,6 @@ public final class RemoveAction extends NodeAction {
}
}
public RemoveAction() {
putValue(Action.SHORT_DESCRIPTION, getName());
}
@Override
public String getName() {
return NbBundle.getMessage(RemoveAction.class, "CTL_RemoveAction");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024, 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
@ -27,6 +27,7 @@ package com.sun.hotspot.igv.coordinator.actions;
import com.sun.hotspot.igv.coordinator.OutlineTopComponent;
import javax.swing.Action;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
@ -42,7 +43,8 @@ public final class RemoveAllAction extends CallableSystemAction {
}
public RemoveAllAction() {
putValue(Action.SHORT_DESCRIPTION, "Remove all graphs and groups");
putValue(Action.SHORT_DESCRIPTION, "Clear workspace");
putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon(iconResource(), true));
}
@Override
@ -62,6 +64,6 @@ public final class RemoveAllAction extends CallableSystemAction {
@Override
public void performAction() {
OutlineTopComponent.findInstance().clear();
OutlineTopComponent.findInstance().clearWorkspace();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 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
@ -27,37 +27,34 @@ package com.sun.hotspot.igv.coordinator.actions;
import com.sun.hotspot.igv.coordinator.OutlineTopComponent;
import javax.swing.Action;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.actions.CallableSystemAction;
/**
*
* @author Thomas Wuerthinger
*/
public final class SaveAllAction extends CallableSystemAction {
public final class SaveAction extends CallableSystemAction {
public SaveAction() {
putValue(Action.SHORT_DESCRIPTION, "Save");
// D is the Control key on most platforms, the Command (meta) key on Macintosh
putValue(Action.ACCELERATOR_KEY, Utilities.stringToKey("D-S"));
putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon(iconResource(), true));
}
@Override
public void performAction() {
final OutlineTopComponent component = OutlineTopComponent.findInstance();
SaveAsAction.save(component.getDocument());
OutlineTopComponent.findInstance().save();
}
@Override
public String getName() {
return NbBundle.getMessage(SaveAllAction.class, "CTL_SaveAllAction");
}
public SaveAllAction() {
putValue(Action.SHORT_DESCRIPTION, "Save all groups to XML file...");
// D is the Control key on most platforms, the Command (meta) key on Macintosh
putValue(Action.ACCELERATOR_KEY, Utilities.stringToKey("D-S"));
return NbBundle.getMessage(SaveAction.class, "CTL_SaveAction");
}
@Override
protected String iconResource() {
return "com/sun/hotspot/igv/coordinator/images/saveall.gif";
return "com/sun/hotspot/igv/coordinator/images/save.png";
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 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
@ -24,75 +24,27 @@
package com.sun.hotspot.igv.coordinator.actions;
import com.sun.hotspot.igv.coordinator.FolderNode;
import com.sun.hotspot.igv.data.Folder;
import com.sun.hotspot.igv.data.GraphDocument;
import com.sun.hotspot.igv.data.Group;
import com.sun.hotspot.igv.data.serialization.Printer;
import com.sun.hotspot.igv.settings.Settings;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.file.Files;
import com.sun.hotspot.igv.coordinator.OutlineTopComponent;
import javax.swing.Action;
import javax.swing.JFileChooser;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.actions.NodeAction;
import org.openide.util.actions.CallableSystemAction;
/**
*
* @author Thomas Wuerthinger
*/
public final class SaveAsAction extends NodeAction {
public final class SaveAsAction extends CallableSystemAction {
public SaveAsAction() {
putValue(Action.SHORT_DESCRIPTION, "Save selected groups to XML file...");
putValue(Action.SHORT_DESCRIPTION, "Save as...");
putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon(iconResource(), true));
}
@Override
protected void performAction(Node[] activatedNodes) {
GraphDocument doc = new GraphDocument();
for (Node node : activatedNodes) {
if (node instanceof FolderNode) {
FolderNode folderNode = (FolderNode) node;
Folder folder = folderNode.getFolder();
if (folder instanceof Group) {
Group group = (Group) folder;
doc.addElement(group);
}
}
}
save(doc);
}
public static void save(GraphDocument doc) {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(ImportAction.getFileFilter());
fc.setCurrentDirectory(new File(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT)));
if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
if (!file.getName().contains(".")) {
file = new File(file.getAbsolutePath() + ".xml");
}
File dir = file;
if (!dir.isDirectory()) {
dir = dir.getParentFile();
}
Settings.get().put(Settings.DIRECTORY, dir.getAbsolutePath());
try {
try (Writer writer = new OutputStreamWriter(Files.newOutputStream(file.toPath()))) {
Printer p = new Printer();
p.export(writer, doc);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void performAction() {
OutlineTopComponent.findInstance().saveAs();
}
@Override
@ -102,7 +54,7 @@ public final class SaveAsAction extends NodeAction {
@Override
protected String iconResource() {
return "com/sun/hotspot/igv/coordinator/images/save.png";
return "com/sun/hotspot/igv/coordinator/images/save_as.gif";
}
@Override
@ -114,17 +66,4 @@ public final class SaveAsAction extends NodeAction {
protected boolean asynchronous() {
return false;
}
@Override
protected boolean enable(Node[] nodes) {
if (nodes.length > 0) {
for (Node n : nodes) {
if (!(n instanceof FolderNode) || ((FolderNode) n).isRootNode()) {
return false;
}
}
return true;
}
return false;
}
}

View File

@ -1,6 +1,3 @@
AdvancedOption_DisplayName_Coordinator=Settings
AdvancedOption_Tooltip_Coordinator=Visualization Tool Settings
CTL_OutlineTopComponent=Outline
CTL_SomeAction=test
HINT_OutlineTopComponent=Displays loaded groups of graphs.
CTL_OutlineTopComponent=Workspace
HINT_OutlineTopComponent=Opened groups of graphs.
OpenIDE-Module-Name=Coordinator

View File

@ -1,8 +1,9 @@
CTL_ImportAction=Open...
CTL_ImportAction=Import...
CTL_OpenAction=Open...
CTL_DiffGraphAction=Difference to current graph
CTL_RemoveAction=Remove selected graphs and groups
CTL_RemoveAllAction=Remove all graphs and groups
CTL_OutlineAction=Outline
CTL_SaveAsAction=Save selected groups...
CTL_SaveAllAction=Save all groups...
CTL_RemoveAllAction=Clear workspace
CTL_OutlineAction=Workspace
CTL_SaveAction=Save
CTL_SaveAsAction=Save as...
CTL_NewFilterAction=New filter...

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -26,8 +26,9 @@
</folder>
<folder name="Actions">
<folder name="File">
<file name="com-sun-hotspot-igv-coordinator-actions-OpenAction.instance"/>
<file name="com-sun-hotspot-igv-coordinator-actions-SaveAction.instance"/>
<file name="com-sun-hotspot-igv-coordinator-actions-SaveAsAction.instance"/>
<file name="com-sun-hotspot-igv-coordinator-actions-SaveAllAction.instance"/>
<file name="com-sun-hotspot-igv-coordinator-actions-ImportAction.instance"/>
<file name="com-sun-hotspot-igv-coordinator-actions-RemoveAction.instance"/>
<file name="com-sun-hotspot-igv-coordinator-actions-RemoveAllAction.instance"/>
@ -55,6 +56,10 @@
<file name="Separator2.instance_hidden"/>
<file name="Separator3.instance_hidden"/>
<file name="SeparatorOpen.instance_hidden"/>
<file name="com-sun-hotspot-igv-coordinator-actions-OpenAction.shadow">
<attr name="originalFile" stringvalue="Actions/File/com-sun-hotspot-igv-coordinator-actions-OpenAction.instance"/>
<attr name="position" intvalue="50"/>
</file>
<file name="com-sun-hotspot-igv-coordinator-actions-ImportAction.shadow">
<attr name="originalFile" stringvalue="Actions/File/com-sun-hotspot-igv-coordinator-actions-ImportAction.instance"/>
<attr name="position" intvalue="100"/>
@ -71,13 +76,13 @@
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
<attr name="position" intvalue="400"/>
</file>
<file name="com-sun-hotspot-igv-coordinator-actions-SaveAction.shadow">
<attr name="originalFile" stringvalue="Actions/File/com-sun-hotspot-igv-coordinator-actions-SaveAction.instance"/>
<attr name="position" intvalue="600"/>
</file>
<file name="com-sun-hotspot-igv-coordinator-actions-SaveAsAction.shadow">
<attr name="originalFile" stringvalue="Actions/File/com-sun-hotspot-igv-coordinator-actions-SaveAsAction.instance"/>
<attr name="position" intvalue="500"/>
</file>
<file name="com-sun-hotspot-igv-coordinator-actions-SaveAllAction.shadow">
<attr name="originalFile" stringvalue="Actions/File/com-sun-hotspot-igv-coordinator-actions-SaveAllAction.instance"/>
<attr name="position" intvalue="600"/>
<attr name="position" intvalue="650"/>
</file>
<file name="SeparatorRemove.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
@ -105,8 +110,8 @@
<file name="org-netbeans-modules-project-ui-RecentProjects.shadow_hidden"/>
<file name="org-netbeans-modules-project-ui-groups-GroupsMenu.shadow_hidden"/>
<file name="org-openide-actions-SaveAction.shadow_hidden"/>
<file name="org-openide-actions-SaveAllAction.shadow_hidden"/>
<file name="org-openide-actions-SaveAsAction.shadow_hidden"/>
<file name="org-openide-actions-SaveAllAction.shadow_hidden"/>
</folder>
<folder name="Edit">

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024, 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
@ -25,7 +25,7 @@ package com.sun.hotspot.igv.data;
import java.util.List;
public interface Folder {
public interface Folder extends Properties.Provider {
void setName(String name);
String getName();
String getDisplayName();
@ -33,4 +33,5 @@ public interface Folder {
void removeElement(FolderElement element);
void addElement(FolderElement group);
ChangedEvent<? extends Folder> getChangedEvent();
Properties getProperties();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024, 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
@ -23,11 +23,12 @@
*/
package com.sun.hotspot.igv.data;
public interface FolderElement {
public interface FolderElement extends Properties.Provider {
ChangedEvent<? extends FolderElement> getDisplayNameChangedEvent();
void setName(String name);
String getName();
String getDisplayName();
void setParent(Folder parent);
Folder getParent();
Properties getProperties();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -54,7 +54,7 @@ public class GraphDocument extends Properties.Entity implements ChangedEventProv
public void addGraphDocument(GraphDocument document) {
if (document != this) {
for (FolderElement e : document.elements) {
for (FolderElement e : document.getElements()) {
e.setParent(this);
this.addElement(e);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -126,13 +126,22 @@ public class Group extends Properties.Entity implements ChangedEventProvider<Gro
@Override
public String getDisplayName() {
String displayName = (getParent() == null ? "" : getParent().getElements().indexOf(this) + 1 + " - ") + getName();
String displayName = (getParent() == null ? "" : getIndex() + 1 + " - ") + getName();
if (getProperties().get("osr") != null) {
displayName += " [OSR]";
}
return displayName;
}
public int getIndex() {
Folder parent = getParent();
if (parent != null) {
return parent.getElements().indexOf(this);
} else {
return -1;
}
}
public String getType() {
return getProperties().get("type");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -23,18 +23,19 @@
*/
package com.sun.hotspot.igv.data.serialization;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.data.*;
import com.sun.hotspot.igv.data.serialization.Printer.GraphContext;
import com.sun.hotspot.igv.data.serialization.Printer.GraphContextAction;
import com.sun.hotspot.igv.data.serialization.XMLParser.ElementHandler;
import com.sun.hotspot.igv.data.serialization.XMLParser.HandoverElementHandler;
import com.sun.hotspot.igv.data.serialization.XMLParser.TopElementHandler;
import com.sun.hotspot.igv.data.services.GroupCallback;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.SwingUtilities;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
@ -49,10 +50,13 @@ import org.xml.sax.XMLReader;
*/
public class Parser implements GraphParser {
public static final String INDENT = " ";
public static final String TOP_ELEMENT = "graphDocument";
public static final String GROUP_ELEMENT = "group";
public static final String GRAPH_ELEMENT = "graph";
public static final String GRAPH_STATES_ELEMENT = "graphStates";
public static final String STATE_ELEMENT = "state";
public static final String STATE_POSITION_DIFFERENCE = "difference";
public static final String POSITION_DIFFERENCE_PROPERTY = "value";
public static final String ROOT_ELEMENT = "graphDocument";
public static final String PROPERTIES_ELEMENT = "properties";
public static final String EDGES_ELEMENT = "edges";
@ -60,15 +64,11 @@ public class Parser implements GraphParser {
public static final String EDGE_ELEMENT = "edge";
public static final String NODE_ELEMENT = "node";
public static final String NODES_ELEMENT = "nodes";
public static final String VISIBLE_NODES_ELEMENT = "visibleNodes";
public static final String ALL_PROPERTY = "all";
public static final String REMOVE_EDGE_ELEMENT = "removeEdge";
public static final String REMOVE_NODE_ELEMENT = "removeNode";
public static final String METHOD_NAME_PROPERTY = "name";
public static final String GROUP_NAME_PROPERTY = "name";
public static final String METHOD_IS_PUBLIC_PROPERTY = "public";
public static final String METHOD_IS_STATIC_PROPERTY = "static";
public static final String TRUE_VALUE = "true";
public static final String NODE_NAME_PROPERTY = "name";
public static final String EDGE_NAME_PROPERTY = "name";
public static final String NODE_ID_PROPERTY = "id";
public static final String FROM_PROPERTY = "from";
public static final String TO_PROPERTY = "to";
@ -89,49 +89,242 @@ public class Parser implements GraphParser {
public static final String BLOCK_ELEMENT = "block";
public static final String SUCCESSORS_ELEMENT = "successors";
public static final String SUCCESSOR_ELEMENT = "successor";
public static final String ASSEMBLY_ELEMENT = "assembly";
public static final String DIFFERENCE_PROPERTY = "difference";
private final TopElementHandler<GraphDocument> xmlDocument = new TopElementHandler<>();
private final TopElementHandler<GraphDocument> xmlData = new TopElementHandler<>();
private final Map<Group, Boolean> differenceEncoding = new HashMap<>();
private final Map<Group, InputGraph> lastParsedGraph = new HashMap<>();
private final GroupCallback groupCallback;
private final GraphDocument callbackDocument;
private final GraphContextAction contextAction;
private final ArrayList<GraphContext> contexts = new ArrayList<>();
private final HashMap<String, Integer> idCache = new HashMap<>();
private final ArrayList<Pair<String, String>> blockConnections = new ArrayList<>();
private int maxId = 0;
private GraphDocument graphDocument;
private final ParseMonitor monitor;
private final ReadableByteChannel channel;
private boolean invokeLater = true;
private int lookupID(String i) {
try {
return Integer.parseInt(i);
} catch (NumberFormatException nfe) {
// ignore
}
Integer id = idCache.get(i);
if (id == null) {
id = maxId++;
idCache.put(i, id);
}
return id;
}
// <graphDocument>
private ElementHandler<GraphDocument, Object> topHandler = new ElementHandler<GraphDocument, Object>(TOP_ELEMENT) {
// <method>
private final ElementHandler<InputMethod, Group> methodHandler = new XMLParser.ElementHandler<>(METHOD_ELEMENT) {
@Override
protected GraphDocument start() throws SAXException {
protected InputMethod start() throws SAXException {
Group group = getParentObject();
InputMethod method = parseMethod(this, group);
group.setMethod(method);
return method;
}
};
// <bytecodes>
private final HandoverElementHandler<InputMethod> bytecodesHandler = new XMLParser.HandoverElementHandler<>(BYTECODES_ELEMENT, true) {
@Override
protected void end(String text) {
getParentObject().setBytecodes(text);
}
};
// <inlined>
private final HandoverElementHandler<InputMethod> inlinedHandler = new XMLParser.HandoverElementHandler<>(INLINE_ELEMENT);
// <inlined><method>
private final ElementHandler<InputMethod, InputMethod> inlinedMethodHandler = new XMLParser.ElementHandler<>(METHOD_ELEMENT) {
@Override
protected InputMethod start() throws SAXException {
InputMethod method = parseMethod(this, getParentObject().getGroup());
getParentObject().addInlined(method);
return method;
}
};
// <nodes>
private final HandoverElementHandler<InputGraph> nodesHandler = new HandoverElementHandler<>(NODES_ELEMENT);
// <controlFlow>
private final HandoverElementHandler<InputGraph> controlFlowHandler = new HandoverElementHandler<>(CONTROL_FLOW_ELEMENT);
private final HandoverElementHandler<InputGraph> graphStatesHandler = new HandoverElementHandler<>(GRAPH_STATES_ELEMENT);
private final ElementHandler<GraphContext, InputGraph> stateHandler = new ElementHandler<>(STATE_ELEMENT) {
@Override
protected GraphContext start() {
InputGraph inputGraph = getParentObject();
GraphContext graphContext = new GraphContext(inputGraph, new AtomicInteger(0), new HashSet<>(), new AtomicBoolean(false));
if (contextAction != null) {
contexts.add(graphContext);
}
return graphContext;
}
};
private final ElementHandler<GraphContext, GraphContext> visibleNodesHandler = new ElementHandler<>(VISIBLE_NODES_ELEMENT) {
@Override
protected GraphContext start() throws SAXException {
String s = readRequiredAttribute(ALL_PROPERTY);
try {
boolean all = Boolean.parseBoolean(s);
getParentObject().showAll().set(all);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
return getParentObject();
}
};
private final ElementHandler<GraphContext, GraphContext> visibleNodeHandler = new ElementHandler<>(NODE_ELEMENT) {
@Override
protected GraphContext start() throws SAXException {
String s = readRequiredAttribute(NODE_ID_PROPERTY);
int nodeID;
try {
nodeID = Integer.parseInt(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
getParentObject().visibleNodes().add(nodeID);
return getParentObject();
}
};
private final ElementHandler<GraphContext, GraphContext> differenceHandler = new ElementHandler<>(STATE_POSITION_DIFFERENCE) {
@Override
protected GraphContext start() throws SAXException {
String s = readRequiredAttribute(POSITION_DIFFERENCE_PROPERTY);
int posDiff;
try {
posDiff = Integer.parseInt(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
getParentObject().posDiff().set(posDiff);
return getParentObject();
}
};
// <block>
private final ElementHandler<InputBlock, InputGraph> blockHandler = new ElementHandler<>(BLOCK_ELEMENT) {
@Override
protected InputBlock start() throws SAXException {
InputGraph graph = getParentObject();
String name = readRequiredAttribute(BLOCK_NAME_PROPERTY);
InputBlock b = graph.addBlock(name);
for (InputNode n : b.getNodes()) {
assert graph.getBlock(n).equals(b);
}
return b;
}
};
// <nodes>
private final HandoverElementHandler<InputBlock> blockNodesHandler = new HandoverElementHandler<>(NODES_ELEMENT);
// <successors>
private final HandoverElementHandler<InputBlock> successorsHandler = new HandoverElementHandler<>(SUCCESSORS_ELEMENT);
// <successor>
private final ElementHandler<InputBlock, InputBlock> successorHandler = new ElementHandler<>(SUCCESSOR_ELEMENT) {
@Override
protected InputBlock start() throws SAXException {
String name = readRequiredAttribute(BLOCK_NAME_PROPERTY);
blockConnections.add(new Pair<>(getParentObject().getName(), name));
return getParentObject();
}
};
// <graph>
private final HandoverElementHandler<InputGraph> edgesHandler = new HandoverElementHandler<>(EDGES_ELEMENT);
// <edge>
private final EdgeElementHandler edgeHandler = new EdgeElementHandler(EDGE_ELEMENT) {
@Override
protected InputEdge start(InputEdge conn) {
InputGraph inputGraph = getParentObject();
inputGraph.addEdge(conn);
return conn;
}
};
// <removeEdge>
private final EdgeElementHandler removeEdgeHandler = new EdgeElementHandler(REMOVE_EDGE_ELEMENT) {
@Override
protected InputEdge start(InputEdge conn) {
getParentObject().removeEdge(conn);
return conn;
}
};
// <properties>
private final HandoverElementHandler<Properties.Provider> propertiesHandler = new HandoverElementHandler<>(PROPERTIES_ELEMENT);
// <property>
private final ElementHandler<String, Properties.Provider> propertyHandler = new XMLParser.ElementHandler<>(PROPERTY_ELEMENT, true) {
@Override
public String start() throws SAXException {
return readRequiredAttribute(PROPERTY_NAME_PROPERTY);
}
@Override
public void end(String text) {
getParentObject().getProperties().setProperty(getObject(), text.trim());
}
};
private int maxId = 0;
// <node>
private final ElementHandler<InputBlock, InputBlock> blockNodeHandler = new ElementHandler<>(NODE_ELEMENT) {
@Override
protected InputBlock start() throws SAXException {
String s = readRequiredAttribute(NODE_ID_PROPERTY);
int id;
try {
id = lookupID(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
getParentObject().addNode(id);
return getParentObject();
}
};
// <node>
private final ElementHandler<InputNode, InputGraph> nodeHandler = new ElementHandler<>(NODE_ELEMENT) {
@Override
protected InputNode start() throws SAXException {
String s = readRequiredAttribute(NODE_ID_PROPERTY);
int id;
try {
id = lookupID(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
InputNode node = new InputNode(id);
getParentObject().addNode(node);
return node;
}
};
// <removeNode>
private final ElementHandler<InputNode, InputGraph> removeNodeHandler = new ElementHandler<>(REMOVE_NODE_ELEMENT) {
@Override
protected InputNode start() throws SAXException {
String s = readRequiredAttribute(NODE_ID_PROPERTY);
int id;
try {
id = lookupID(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
return getParentObject().removeNode(id);
}
};
private GraphDocument graphDocument;
// <graphDocument>
private final ElementHandler<GraphDocument, Object> topHandler = new ElementHandler<>(TOP_ELEMENT) {
@Override
protected GraphDocument start() {
graphDocument = new GraphDocument();
return graphDocument;
}
};
// <group>
private ElementHandler<Group, Folder> groupHandler = new XMLParser.ElementHandler<Group, Folder>(GROUP_ELEMENT) {
private final ElementHandler<Group, Folder> groupHandler = new XMLParser.ElementHandler<>(GROUP_ELEMENT) {
@Override
protected Group start() throws SAXException {
final Group group = new Group(this.getParentObject());
protected Group start() {
final Folder folder = getParentObject();
final Group group = new Group(folder);
String differenceProperty = this.readAttribute(DIFFERENCE_PROPERTY);
Parser.this.differenceEncoding.put(group, (differenceProperty != null && (differenceProperty.equals("1") || differenceProperty.equals("true"))));
@ -141,13 +334,11 @@ public class Parser implements GraphParser {
monitor.setState(group.getName());
}
final Folder parent = getParentObject();
if (groupCallback == null || parent instanceof Group) {
Runnable addToParent = () -> parent.addElement(group);
if (callbackDocument == null || folder instanceof Group) {
if (invokeLater) {
SwingUtilities.invokeLater(addToParent);
SwingUtilities.invokeLater(() -> folder.addElement(group));
} else {
addToParent.run();
folder.addElement(group);
}
}
@ -155,62 +346,20 @@ public class Parser implements GraphParser {
}
@Override
protected void end(String text) throws SAXException {
}
};
// <method>
private ElementHandler<InputMethod, Group> methodHandler = new XMLParser.ElementHandler<InputMethod, Group>(METHOD_ELEMENT) {
@Override
protected InputMethod start() throws SAXException {
InputMethod method = parseMethod(this, getParentObject());
getParentObject().setMethod(method);
return method;
}
};
private InputMethod parseMethod(XMLParser.ElementHandler<?,?> handler, Group group) throws SAXException {
String s = handler.readRequiredAttribute(METHOD_BCI_PROPERTY);
int bci = 0;
try {
bci = Integer.parseInt(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
InputMethod method = new InputMethod(group, handler.readRequiredAttribute(METHOD_NAME_PROPERTY), handler.readRequiredAttribute(METHOD_SHORT_NAME_PROPERTY), bci);
return method;
}
// <bytecodes>
private HandoverElementHandler<InputMethod> bytecodesHandler = new XMLParser.HandoverElementHandler<InputMethod>(BYTECODES_ELEMENT, true) {
@Override
protected void end(String text) throws SAXException {
getParentObject().setBytecodes(text);
}
};
// <inlined>
private HandoverElementHandler<InputMethod> inlinedHandler = new XMLParser.HandoverElementHandler<>(INLINE_ELEMENT);
// <inlined><method>
private ElementHandler<InputMethod, InputMethod> inlinedMethodHandler = new XMLParser.ElementHandler<InputMethod, InputMethod>(METHOD_ELEMENT) {
@Override
protected InputMethod start() throws SAXException {
InputMethod method = parseMethod(this, getParentObject().getGroup());
getParentObject().addInlined(method);
return method;
protected void end(String text) {
}
};
// <graph>
private ElementHandler<InputGraph, Group> graphHandler = new XMLParser.ElementHandler<InputGraph, Group>(GRAPH_ELEMENT) {
private final ElementHandler<InputGraph, Group> graphHandler = new XMLParser.ElementHandler<>(GRAPH_ELEMENT) {
@Override
protected InputGraph start() throws SAXException {
protected InputGraph start() {
Group group = getParentObject();
String name = readAttribute(GRAPH_NAME_PROPERTY);
InputGraph curGraph = new InputGraph(name);
if (differenceEncoding.get(getParentObject())) {
InputGraph previous = lastParsedGraph.get(getParentObject());
lastParsedGraph.put(getParentObject(), curGraph);
if (differenceEncoding.get(group)) {
InputGraph previous = lastParsedGraph.get(group);
lastParsedGraph.put(group, curGraph);
if (previous != null) {
for (InputNode n : previous.getNodes()) {
curGraph.addNode(n);
@ -228,8 +377,8 @@ public class Parser implements GraphParser {
}
@Override
protected void end(String text) throws SAXException {
// NOTE: Some graphs intentionally don't provide blocks. Instead
protected void end(String text) {
// NOTE: Some graphs intentionally don't provide blocks. Instead,
// they later generate the blocks from other information such
// as node properties (example: ServerCompilerScheduler).
// Thus, we shouldn't assign nodes that don't belong to any
@ -237,11 +386,12 @@ public class Parser implements GraphParser {
// defined and nodes are assigned to them.
final InputGraph graph = getObject();
final Group parent = getParentObject();
if (graph.getBlocks().size() > 0) {
if (!graph.getBlocks().isEmpty()) {
boolean blocksContainNodes = false;
for (InputBlock b : graph.getBlocks()) {
if (b.getNodes().size() > 0) {
if (!b.getNodes().isEmpty()) {
blocksContainNodes = true;
break;
}
@ -252,7 +402,7 @@ public class Parser implements GraphParser {
blockConnections.clear();
} else {
// Blocks and their nodes defined: add other nodes to an
// artificial "no block" block
// artificial "no block" block
InputBlock noBlock = null;
for (InputNode n : graph.getNodes()) {
if (graph.getBlock(n) == null) {
@ -278,97 +428,154 @@ public class Parser implements GraphParser {
}
blockConnections.clear();
Runnable addToParent = () -> parent.addElement(graph);
if (invokeLater) {
SwingUtilities.invokeLater(addToParent);
SwingUtilities.invokeLater(() -> parent.addElement(graph));
} else {
addToParent.run();
parent.addElement(graph);
}
if (contextAction != null) {
for (GraphContext ctx : contexts) {
contextAction.performAction(ctx);
}
}
contexts.clear();
}
};
// <properties>
private final HandoverElementHandler<Group> groupPropertiesHandler = new HandoverElementHandler<>(PROPERTIES_ELEMENT) {
@Override
public void end(String text) {
final Group group = getParentObject();
if (callbackDocument != null && group.getParent() instanceof GraphDocument) {
group.setParent(callbackDocument);
if (invokeLater) {
SwingUtilities.invokeLater(() -> callbackDocument.addElement(group));
} else {
callbackDocument.addElement(group);
}
}
}
};
// <nodes>
private HandoverElementHandler<InputGraph> nodesHandler = new HandoverElementHandler<>(NODES_ELEMENT);
// <controlFlow>
private HandoverElementHandler<InputGraph> controlFlowHandler = new HandoverElementHandler<>(CONTROL_FLOW_ELEMENT);
// <block>
private ElementHandler<InputBlock, InputGraph> blockHandler = new ElementHandler<InputBlock, InputGraph>(BLOCK_ELEMENT) {
@Override
protected InputBlock start() throws SAXException {
InputGraph graph = getParentObject();
String name = readRequiredAttribute(BLOCK_NAME_PROPERTY);
InputBlock b = graph.addBlock(name);
for (InputNode n : b.getNodes()) {
assert graph.getBlock(n).equals(b);
public Parser(ReadableByteChannel channel, ParseMonitor monitor, GraphDocument callbackDocument, GraphContextAction contextAction) {
this.callbackDocument = callbackDocument;
this.contextAction = contextAction;
this.monitor = monitor;
this.channel = channel;
// Initialize dependencies
xmlData.addChild(topHandler);
topHandler.addChild(groupHandler);
groupHandler.addChild(methodHandler);
groupHandler.addChild(graphHandler);
groupHandler.addChild(groupHandler);
methodHandler.addChild(inlinedHandler);
methodHandler.addChild(bytecodesHandler);
inlinedHandler.addChild(inlinedMethodHandler);
inlinedMethodHandler.addChild(bytecodesHandler);
inlinedMethodHandler.addChild(inlinedHandler);
graphHandler.addChild(nodesHandler);
graphHandler.addChild(edgesHandler);
graphHandler.addChild(controlFlowHandler);
graphHandler.addChild(graphStatesHandler);
controlFlowHandler.addChild(blockHandler);
graphStatesHandler.addChild(stateHandler);
stateHandler.addChild(differenceHandler);
stateHandler.addChild(visibleNodesHandler);
visibleNodesHandler.addChild(visibleNodeHandler);
blockHandler.addChild(successorsHandler);
successorsHandler.addChild(successorHandler);
blockHandler.addChild(blockNodesHandler);
blockNodesHandler.addChild(blockNodeHandler);
nodesHandler.addChild(nodeHandler);
nodesHandler.addChild(removeNodeHandler);
edgesHandler.addChild(edgeHandler);
edgesHandler.addChild(removeEdgeHandler);
methodHandler.addChild(propertiesHandler);
inlinedMethodHandler.addChild(propertiesHandler);
topHandler.addChild(propertiesHandler);
groupHandler.addChild(groupPropertiesHandler);
graphHandler.addChild(propertiesHandler);
nodeHandler.addChild(propertiesHandler);
propertiesHandler.addChild(propertyHandler);
groupPropertiesHandler.addChild(propertyHandler);
}
private int lookupID(String i) {
try {
return Integer.parseInt(i);
} catch (NumberFormatException nfe) {
// ignore
}
Integer id = idCache.get(i);
if (id == null) {
id = maxId++;
idCache.put(i, id);
}
return id;
}
private InputMethod parseMethod(XMLParser.ElementHandler<?, ?> handler, Group group) throws SAXException {
String s = handler.readRequiredAttribute(METHOD_BCI_PROPERTY);
int bci;
try {
bci = Integer.parseInt(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
return new InputMethod(group, handler.readRequiredAttribute(METHOD_NAME_PROPERTY), handler.readRequiredAttribute(METHOD_SHORT_NAME_PROPERTY), bci);
}
// Returns a new GraphDocument object deserialized from an XML input source.
@Override
public GraphDocument parse() throws IOException {
if (monitor != null) {
monitor.setState("Starting parsing");
}
try {
XMLReader reader = createReader();
// To enforce using English for non-English users, we must use Locale.ROOT rather than Locale.ENGLISH
reader.setProperty("http://apache.org/xml/properties/locale", Locale.ROOT);
reader.setContentHandler(new XMLParser(xmlData, monitor));
reader.parse(new InputSource(Channels.newInputStream(channel)));
} catch (SAXException ex) {
if (!(ex instanceof SAXParseException) || !"XML document structures must start and end within the same entity.".equals(ex.getMessage())) {
throw new IOException(ex);
}
return b;
}
};
// <nodes>
private HandoverElementHandler<InputBlock> blockNodesHandler = new HandoverElementHandler<>(NODES_ELEMENT);
// <node>
private ElementHandler<InputBlock, InputBlock> blockNodeHandler = new ElementHandler<InputBlock, InputBlock>(NODE_ELEMENT) {
@Override
protected InputBlock start() throws SAXException {
String s = readRequiredAttribute(NODE_ID_PROPERTY);
int id = 0;
try {
id = lookupID(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
getParentObject().addNode(id);
return getParentObject();
if (monitor != null) {
monitor.setState("Finished parsing");
}
};
// <successors>
private HandoverElementHandler<InputBlock> successorsHandler = new HandoverElementHandler<>(SUCCESSORS_ELEMENT);
// <successor>
private ElementHandler<InputBlock, InputBlock> successorHandler = new ElementHandler<InputBlock, InputBlock>(SUCCESSOR_ELEMENT) {
@Override
protected InputBlock start() throws SAXException {
String name = readRequiredAttribute(BLOCK_NAME_PROPERTY);
blockConnections.add(new Pair<>(getParentObject().getName(), name));
return getParentObject();
}
};
// <node>
private ElementHandler<InputNode, InputGraph> nodeHandler = new ElementHandler<InputNode, InputGraph>(NODE_ELEMENT) {
return graphDocument;
}
@Override
protected InputNode start() throws SAXException {
String s = readRequiredAttribute(NODE_ID_PROPERTY);
int id = 0;
try {
id = lookupID(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
InputNode node = new InputNode(id);
getParentObject().addNode(node);
return node;
}
};
// <removeNode>
private ElementHandler<InputNode, InputGraph> removeNodeHandler = new ElementHandler<InputNode, InputGraph>(REMOVE_NODE_ELEMENT) {
// Whether the parser is allowed to defer connecting the parsed elements.
// Setting to false is useful for synchronization in unit tests.
public void setInvokeLater(boolean invokeLater) {
this.invokeLater = invokeLater;
}
@Override
protected InputNode start() throws SAXException {
String s = readRequiredAttribute(NODE_ID_PROPERTY);
int id = 0;
try {
id = lookupID(s);
} catch (NumberFormatException e) {
throw new SAXException(e);
}
return getParentObject().removeNode(id);
private XMLReader createReader() throws SAXException {
try {
SAXParserFactory pFactory = SAXParserFactory.newInstance();
pFactory.setValidating(false);
pFactory.setNamespaceAware(true);
return pFactory.newSAXParser().getXMLReader();
} catch (ParserConfigurationException ex) {
throw new SAXException(ex);
}
};
// <graph>
private HandoverElementHandler<InputGraph> edgesHandler = new HandoverElementHandler<>(EDGES_ELEMENT);
}
// Local class for edge elements
private class EdgeElementHandler extends ElementHandler<InputEdge, InputGraph> {
@ -381,10 +588,10 @@ public class Parser implements GraphParser {
protected InputEdge start() throws SAXException {
int fromIndex = 0;
int toIndex = 0;
int from = -1;
int to = -1;
String label = null;
String type = null;
int from;
int to;
String label;
String type;
try {
String fromIndexString = readAttribute(FROM_INDEX_PROPERTY);
@ -413,148 +620,8 @@ public class Parser implements GraphParser {
return start(conn);
}
protected InputEdge start(InputEdge conn) throws SAXException {
protected InputEdge start(InputEdge conn) {
return conn;
}
}
// <edge>
private EdgeElementHandler edgeHandler = new EdgeElementHandler(EDGE_ELEMENT) {
@Override
protected InputEdge start(InputEdge conn) throws SAXException {
getParentObject().addEdge(conn);
return conn;
}
};
// <removeEdge>
private EdgeElementHandler removeEdgeHandler = new EdgeElementHandler(REMOVE_EDGE_ELEMENT) {
@Override
protected InputEdge start(InputEdge conn) throws SAXException {
getParentObject().removeEdge(conn);
return conn;
}
};
// <properties>
private HandoverElementHandler<Properties.Provider> propertiesHandler = new HandoverElementHandler<>(PROPERTIES_ELEMENT);
// <properties>
private HandoverElementHandler<Group> groupPropertiesHandler = new HandoverElementHandler<Group>(PROPERTIES_ELEMENT) {
@Override
public void end(String text) throws SAXException {
if (groupCallback != null && getParentObject().getParent() instanceof GraphDocument) {
final Group group = getParentObject();
Runnable addStarted = () -> groupCallback.started(group);
if (invokeLater) {
SwingUtilities.invokeLater(addStarted);
} else {
addStarted.run();
}
}
}
};
// <property>
private ElementHandler<String, Properties.Provider> propertyHandler = new XMLParser.ElementHandler<String, Properties.Provider>(PROPERTY_ELEMENT, true) {
@Override
public String start() throws SAXException {
return readRequiredAttribute(PROPERTY_NAME_PROPERTY);
}
@Override
public void end(String text) {
getParentObject().getProperties().setProperty(getObject(), text.trim());
}
};
public Parser(ReadableByteChannel channel) {
this(channel, null, null);
}
public Parser(ReadableByteChannel channel, ParseMonitor monitor, GroupCallback groupCallback) {
this.groupCallback = groupCallback;
this.monitor = monitor;
this.channel = channel;
// Initialize dependencies
xmlDocument.addChild(topHandler);
topHandler.addChild(groupHandler);
groupHandler.addChild(methodHandler);
groupHandler.addChild(graphHandler);
groupHandler.addChild(groupHandler);
methodHandler.addChild(inlinedHandler);
methodHandler.addChild(bytecodesHandler);
inlinedHandler.addChild(inlinedMethodHandler);
inlinedMethodHandler.addChild(bytecodesHandler);
inlinedMethodHandler.addChild(inlinedHandler);
graphHandler.addChild(nodesHandler);
graphHandler.addChild(edgesHandler);
graphHandler.addChild(controlFlowHandler);
controlFlowHandler.addChild(blockHandler);
blockHandler.addChild(successorsHandler);
successorsHandler.addChild(successorHandler);
blockHandler.addChild(blockNodesHandler);
blockNodesHandler.addChild(blockNodeHandler);
nodesHandler.addChild(nodeHandler);
nodesHandler.addChild(removeNodeHandler);
edgesHandler.addChild(edgeHandler);
edgesHandler.addChild(removeEdgeHandler);
methodHandler.addChild(propertiesHandler);
inlinedMethodHandler.addChild(propertiesHandler);
topHandler.addChild(propertiesHandler);
groupHandler.addChild(groupPropertiesHandler);
graphHandler.addChild(propertiesHandler);
nodeHandler.addChild(propertiesHandler);
propertiesHandler.addChild(propertyHandler);
groupPropertiesHandler.addChild(propertyHandler);
}
// Returns a new GraphDocument object deserialized from an XML input source.
@Override
public GraphDocument parse() throws IOException {
if (monitor != null) {
monitor.setState("Starting parsing");
}
try {
XMLReader reader = createReader();
// To enforce using English for non-English users, we must use Locale.ROOT rather than Locale.ENGLISH
reader.setProperty("http://apache.org/xml/properties/locale", Locale.ROOT);
reader.setContentHandler(new XMLParser(xmlDocument, monitor));
reader.parse(new InputSource(Channels.newInputStream(channel)));
} catch (SAXException ex) {
if (!(ex instanceof SAXParseException) || !"XML document structures must start and end within the same entity.".equals(ex.getMessage())) {
throw new IOException(ex);
}
}
if (monitor != null) {
monitor.setState("Finished parsing");
}
return graphDocument;
}
// Whether the parser is allowed to defer connecting the parsed elements.
// Setting to false is useful for synchronization in unit tests.
public void setInvokeLater(boolean invokeLater) {
this.invokeLater = invokeLater;
}
private XMLReader createReader() throws SAXException {
try {
SAXParserFactory pfactory = SAXParserFactory.newInstance();
pfactory.setValidating(false);
pfactory.setNamespaceAware(true);
return pfactory.newSAXParser().getXMLReader();
} catch (ParserConfigurationException ex) {
throw new SAXException(ex);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -25,10 +25,13 @@ package com.sun.hotspot.igv.data.serialization;
import com.sun.hotspot.igv.data.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
*
@ -36,76 +39,47 @@ import java.util.Set;
*/
public class Printer {
private final InputStream in;
public Printer() {
this(null);
}
public Printer(InputStream inputStream) {
this.in = inputStream;
}
public void export(Writer writer, GraphDocument document) {
public static void exportGraphDocument(Writer writer, Folder folder, List<GraphContext> contexts) {
XMLWriter xmlWriter = new XMLWriter(writer);
try {
export(xmlWriter, document);
xmlWriter.startTag(Parser.ROOT_ELEMENT);
xmlWriter.writeProperties(folder.getProperties());
for (FolderElement e : folder.getElements()) {
if (e instanceof Group group) {
exportGroup(xmlWriter, group, contexts);
} else if (e instanceof InputGraph graph) {
exportInputGraph(xmlWriter, graph, null, false, contexts);
}
}
xmlWriter.endTag();
xmlWriter.flush();
} catch (IOException ignored) {}
}
private void export(XMLWriter xmlWriter, GraphDocument document) throws IOException {
xmlWriter.startTag(Parser.ROOT_ELEMENT);
xmlWriter.writeProperties(document.getProperties());
for (FolderElement e : document.getElements()) {
if (e instanceof Group) {
export(xmlWriter, (Group) e);
} else if (e instanceof InputGraph) {
export(xmlWriter, (InputGraph)e, null, false);
}
}
xmlWriter.endTag();
xmlWriter.flush();
}
private void export(XMLWriter writer, Group g) throws IOException {
private static void exportGroup(XMLWriter writer, Group g, List<GraphContext> contexts) throws IOException {
Properties attributes = new Properties();
attributes.setProperty("difference", Boolean.toString(true));
writer.startTag(Parser.GROUP_ELEMENT, attributes);
writer.writeProperties(g.getProperties());
boolean shouldExport = true;
if (in != null) {
char c = (char) in.read();
if (c != 'y') {
shouldExport = false;
}
if (g.getMethod() != null) {
exportInputMethod(writer, g.getMethod());
}
if (shouldExport) {
if (g.getMethod() != null) {
export(writer, g.getMethod());
}
InputGraph previous = null;
for (FolderElement e : g.getElements()) {
if (e instanceof InputGraph) {
InputGraph graph = (InputGraph) e;
export(writer, graph, previous, true);
previous = graph;
} else if (e instanceof Group) {
export(writer, (Group) e);
}
InputGraph previous = null;
for (FolderElement e : g.getElements()) {
if (e instanceof InputGraph graph) {
exportInputGraph(writer, graph, previous, true, contexts);
previous = graph;
} else if (e instanceof Group group) {
exportGroup(writer, group, contexts);
}
}
writer.endTag();
}
public void export(XMLWriter writer, InputGraph graph, InputGraph previous, boolean difference) throws IOException {
private static void exportInputGraph(XMLWriter writer, InputGraph graph, InputGraph previous, boolean difference, List<GraphContext> contexts) throws IOException {
writer.startTag(Parser.GRAPH_ELEMENT);
writer.writeProperties(graph.getProperties());
writer.startTag(Parser.NODES_ELEMENT);
@ -135,11 +109,11 @@ public class Printer {
if (!difference || !equal.contains(n)) {
writer.startTag(Parser.NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, Integer.toString(n.getId())));
writer.writeProperties(n.getProperties());
writer.endTag();
writer.endTag(); // Parser.NODE_ELEMENT
}
}
writer.endTag();
writer.endTag(); // Parser.NODES_ELEMENT
writer.startTag(Parser.EDGES_ELEMENT);
Set<InputEdge> removedEdges = new HashSet<>();
@ -169,45 +143,78 @@ public class Printer {
}
}
writer.endTag();
writer.endTag(); // Parser.EDGES_ELEMENT
writer.startTag(Parser.CONTROL_FLOW_ELEMENT);
for (InputBlock b : graph.getBlocks()) {
writer.startTag(Parser.BLOCK_ELEMENT, new Properties(Parser.BLOCK_NAME_PROPERTY, b.getName()));
if (b.getSuccessors().size() > 0) {
if (!b.getSuccessors().isEmpty()) {
writer.startTag(Parser.SUCCESSORS_ELEMENT);
for (InputBlock s : b.getSuccessors()) {
writer.simpleTag(Parser.SUCCESSOR_ELEMENT, new Properties(Parser.BLOCK_NAME_PROPERTY, s.getName()));
}
writer.endTag();
writer.endTag(); // Parser.SUCCESSORS_ELEMENT
}
if (b.getNodes().size() > 0) {
writer.startTag(Parser.NODES_ELEMENT);
if (!b.getNodes().isEmpty()) {
writer.startTag(Parser.NODES_ELEMENT);
for (InputNode n : b.getNodes()) {
writer.simpleTag(Parser.NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, n.getId() + ""));
}
writer.endTag();
writer.endTag(); // Parser.NODES_ELEMENT
}
writer.endTag();
writer.endTag(); // Parser.BLOCK_ELEMENT
}
writer.endTag();
writer.endTag();
writer.endTag(); // Parser.CONTROL_FLOW_ELEMENT
exportStates(writer, graph, contexts);
writer.endTag(); // Parser.GRAPH_ELEMENT
}
private void export(XMLWriter w, InputMethod method) throws IOException {
private static void exportStates(XMLWriter writer, InputGraph exportingGraph, List<GraphContext> contexts) throws IOException {
List<GraphContext> contextsContainingGraph = contexts.stream()
.filter(context -> context.inputGraph().equals(exportingGraph))
.toList();
if (contextsContainingGraph.isEmpty()) {
return;
}
writer.startTag(Parser.GRAPH_STATES_ELEMENT);
for (GraphContext context : contextsContainingGraph) {
assert exportingGraph == context.inputGraph();
writer.startTag(Parser.STATE_ELEMENT);
writer.simpleTag(Parser.STATE_POSITION_DIFFERENCE,
new Properties(Parser.POSITION_DIFFERENCE_PROPERTY, Integer.toString(context.posDiff().get())));
writer.startTag(Parser.VISIBLE_NODES_ELEMENT, new Properties(Parser.ALL_PROPERTY, Boolean.toString(context.showAll().get())));
for (Integer hiddenNodeID : context.visibleNodes()) {
writer.simpleTag(Parser.NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, hiddenNodeID.toString()));
}
writer.endTag(); // Parser.VISIBLE_NODES_ELEMENT
writer.endTag(); // Parser.STATES_ELEMENT
}
writer.endTag(); // Parser.GRAPH_STATE_ELEMENT
}
private static void exportInputMethod(XMLWriter w, InputMethod method) throws IOException {
w.startTag(Parser.METHOD_ELEMENT, new Properties(Parser.METHOD_BCI_PROPERTY, method.getBci() + "", Parser.METHOD_NAME_PROPERTY, method.getName(), Parser.METHOD_SHORT_NAME_PROPERTY, method.getShortName()));
w.writeProperties(method.getProperties());
if (method.getInlined().size() > 0) {
if (!method.getInlined().isEmpty()) {
w.startTag(Parser.INLINE_ELEMENT);
for (InputMethod m : method.getInlined()) {
export(w, m);
exportInputMethod(w, m);
}
w.endTag();
}
@ -229,7 +236,7 @@ public class Printer {
w.endTag();
}
private Properties createProperties(InputEdge edge) {
private static Properties createProperties(InputEdge edge) {
Properties p = new Properties();
if (edge.getToIndex() != 0) {
p.setProperty(Parser.TO_INDEX_PROPERTY, Integer.toString(edge.getToIndex()));
@ -242,4 +249,10 @@ public class Printer {
p.setProperty(Parser.TYPE_PROPERTY, edge.getType());
return p;
}
public record GraphContext(InputGraph inputGraph, AtomicInteger posDiff, Set<Integer> visibleNodes, AtomicBoolean showAll) { }
public interface GraphContextAction {
void performAction(GraphContext context);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -31,7 +31,7 @@ import com.sun.hotspot.igv.data.InputGraph;
*/
public interface GraphViewer {
void view(InputGraph graph, boolean newTab);
InputGraph view(InputGraph graph, boolean newTab);
void viewDifference(InputGraph firstGraph, InputGraph secondGraph);
InputGraph viewDifference(InputGraph firstGraph, InputGraph secondGraph);
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 1998, 2015, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.data.services;
import com.sun.hotspot.igv.data.Group;
/**
*
* @author Thomas Wuerthinger
*/
public interface GroupCallback {
public void started(Group g);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024, 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
@ -32,6 +32,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.ArrayList;
import java.util.HashSet;
import org.junit.*;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@ -62,19 +64,18 @@ public class ParserTest {
}
private void test(GraphDocument document) {
final Printer printer = new Printer();
final CharArrayWriter writer = new CharArrayWriter();
printer.export(writer, document);
Printer.exportGraphDocument(writer, document, new ArrayList<>());
test(document, writer.toString());
}
private void test(GraphDocument document, String xmlString) {
InputStream in = new ByteArrayInputStream(xmlString.getBytes(UTF_8));
try {
Parser parser = new Parser(Channels.newChannel(in));
Parser parser = new Parser(Channels.newChannel(in), null, null, null);
parser.setInvokeLater(false);
final GraphDocument parsedDocument = parser.parse();
Util.assertGraphDocumentEquals(document, parsedDocument);
final GraphDocument exportData = parser.parse();
Util.assertGraphDocumentEquals(document, exportData);
} catch (IOException ex) {
fail(ex.toString());
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2012, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.connection;
import com.sun.hotspot.igv.data.serialization.Parser;
import com.sun.hotspot.igv.data.services.GroupCallback;
import java.io.IOException;
import java.nio.channels.SocketChannel;
import org.openide.util.Exceptions;
public class Client implements Runnable {
private final SocketChannel socket;
private final GroupCallback callback;
public Client(SocketChannel socket, GroupCallback callback) {
this.callback = callback;
this.socket = socket;
}
@Override
public void run() {
try {
final SocketChannel channel = socket;
channel.configureBlocking(true);
channel.socket().getOutputStream().write('y');
new Parser(channel, null, callback).parse();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} finally {
try {
socket.close();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024, 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
@ -24,7 +24,9 @@
*/
package com.sun.hotspot.igv.connection;
import com.sun.hotspot.igv.data.services.GroupCallback;
import com.sun.hotspot.igv.data.GraphDocument;
import com.sun.hotspot.igv.data.serialization.Parser;
import com.sun.hotspot.igv.data.serialization.Printer.GraphContextAction;
import com.sun.hotspot.igv.settings.Settings;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -32,9 +34,6 @@ import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.RequestProcessor;
/**
*
@ -42,13 +41,16 @@ import org.openide.util.RequestProcessor;
*/
public class Server implements PreferenceChangeListener {
private ServerSocketChannel serverSocket;
private final GroupCallback callback;
private final GraphDocument graphDocument;
private final GraphContextAction contextAction;
private int port;
private Runnable serverRunnable;
public Server(GroupCallback callback) {
this.callback = callback;
initializeNetwork();
private volatile boolean isServerRunning;
public Server(GraphDocument graphDocument, GraphContextAction contextAction) {
this.graphDocument = graphDocument;
this.contextAction = contextAction;
port = Integer.parseInt(Settings.get().get(Settings.PORT, Settings.PORT_DEFAULT));
Settings.get().addPreferenceChangeListener(this);
}
@ -56,46 +58,65 @@ public class Server implements PreferenceChangeListener {
public void preferenceChange(PreferenceChangeEvent e) {
int curPort = Integer.parseInt(Settings.get().get(Settings.PORT, Settings.PORT_DEFAULT));
if (curPort != port) {
initializeNetwork();
port = curPort;
shutdownServer();
startServer();
}
}
private void initializeNetwork() {
int curPort = Integer.parseInt(Settings.get().get(Settings.PORT, Settings.PORT_DEFAULT));
this.port = curPort;
public void startServer() {
isServerRunning = true;
try {
serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress(curPort));
} catch (Throwable ex) {
NotifyDescriptor message = new NotifyDescriptor.Message("Could not create server. Listening for incoming data is disabled.", NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notifyLater(message);
serverSocket.bind(new InetSocketAddress(port));
} catch (IOException ex) {
ex.printStackTrace();
return;
}
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
try {
SocketChannel clientSocket = serverSocket.accept();
if (serverRunnable != this) {
clientSocket.close();
return;
}
RequestProcessor.getDefault().post(new Client(clientSocket, callback), 0, Thread.MAX_PRIORITY);
} catch (IOException ex) {
serverSocket = null;
NotifyDescriptor message = new NotifyDescriptor.Message("Error during listening for incoming connections. Listening for incoming data is disabled.", NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notifyLater(message);
Runnable client = () -> {
while (isServerRunning) {
try {
SocketChannel clientSocket = serverSocket.accept();
if (!isServerRunning) {
clientSocket.close();
return;
}
new Thread(() -> {
try (clientSocket) {
clientSocket.configureBlocking(true);
clientSocket.socket().getOutputStream().write('y');
new Parser(clientSocket, null, graphDocument, contextAction).parse();
} catch (IOException ignored) {}
}).start();
} catch (IOException ex) {
if (isServerRunning) {
ex.printStackTrace();
}
return;
}
}
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
};
serverRunnable = runnable;
new Thread(client).start();
}
RequestProcessor.getDefault().post(runnable, 0, Thread.MAX_PRIORITY);
public void shutdownServer() {
isServerRunning = false;
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

View File

@ -652,7 +652,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer, DoubleCl
Rectangle bounds = rootWidget.getBounds();
if (bounds != null) {
Point location = rootWidget.getLocation();
centerRectangle(new Rectangle(location.x, location.y, bounds.width, bounds.height));
centerRectangle(new Rectangle(location.x, location.y, bounds.width, bounds.height), false);
}
}
}
@ -872,7 +872,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer, DoubleCl
private void gotoBlock(final Block block) {
BlockWidget bw = getWidget(block.getInputBlock());
if (bw != null) {
centerRectangle(bw.getBounds());
centerRectangle(bw.getBounds(), true);
}
}
@ -919,26 +919,28 @@ public class DiagramScene extends ObjectScene implements DiagramViewer, DoubleCl
}
}
if (overallRect != null) {
centerRectangle(overallRect);
centerRectangle(overallRect, true);
}
}
private void centerRectangle(Rectangle r) {
private void centerRectangle(Rectangle r, boolean zoomToFit) {
Rectangle rect = convertSceneToView(r);
Rectangle viewRect = scrollPane.getViewport().getViewRect();
double factor = Math.min(viewRect.getWidth() / rect.getWidth(), viewRect.getHeight() / rect.getHeight());
double zoomFactor = getZoomFactor();
double newZoomFactor = zoomFactor * factor;
if (factor < 1.0 || zoomFactor < 1.0) {
newZoomFactor = Math.min(1.0, newZoomFactor);
centredZoom(newZoomFactor, null);
factor = newZoomFactor / zoomFactor;
rect.x *= factor;
rect.y *= factor;
rect.width *= factor;
rect.height *= factor;
if (zoomToFit) {
double factor = Math.min(viewRect.getWidth() / rect.getWidth(), viewRect.getHeight() / rect.getHeight());
double zoomFactor = getZoomFactor();
double newZoomFactor = zoomFactor * factor;
if (factor < 1.0 || zoomFactor < 1.0) {
newZoomFactor = Math.min(1.0, newZoomFactor);
centredZoom(newZoomFactor, null);
factor = newZoomFactor / zoomFactor;
rect.x *= factor;
rect.y *= factor;
rect.width *= factor;
rect.height *= factor;
}
}
viewRect.x = rect.x + rect.width / 2 - viewRect.width / 2;
viewRect.y = rect.y + rect.height / 2 - viewRect.height / 2;
// Ensure to be within area

View File

@ -332,6 +332,14 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
final HashSet<Integer> allNodes = new HashSet<>(getGroup().getAllNodes());
allNodes.removeAll(nodes);
setHiddenNodes(allNodes);
}
public Set<Integer> getVisibleNodes() {
final Set<Integer> visibleNodes = new HashSet<>(getGraph().getNodesAsSet());
visibleNodes.removeAll(hiddenNodes);
return visibleNodes;
}
public void setHiddenNodes(Set<Integer> nodes) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -125,8 +125,7 @@ public final class EditorTopComponent extends TopComponent implements TopCompone
Group group = diagramViewModel.getGroup();
group.getChangedEvent().addListener(g -> closeOnRemovedOrEmptyGroup());
if (group.getParent() instanceof GraphDocument) {
final GraphDocument doc = (GraphDocument) group.getParent();
if (group.getParent() instanceof GraphDocument doc) {
doc.getChangedEvent().addListener(d -> closeOnRemovedOrEmptyGroup());
}
@ -309,8 +308,7 @@ public final class EditorTopComponent extends TopComponent implements TopCompone
l.add(m.getSelectedTopComponent());
l.addAll(Arrays.asList(manager.getOpenedTopComponents(m)));
for (TopComponent t : l) {
if (t instanceof EditorTopComponent) {
EditorTopComponent etc = (EditorTopComponent) t;
if (t instanceof EditorTopComponent etc) {
if (etc.getModel().getGroup().getGraphs().contains(graph)) {
return etc;
}
@ -320,17 +318,31 @@ public final class EditorTopComponent extends TopComponent implements TopCompone
return null;
}
public static void closeAllInstances() {
WindowManager manager = WindowManager.getDefault();
for (Mode mode : manager.getModes()) {
TopComponent[] openedTopComponents = manager.getOpenedTopComponents(mode);
for (TopComponent tc : openedTopComponents) {
if (tc instanceof EditorTopComponent etc) {
etc.close();
}
}
}
}
@Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_NEVER;
}
private void closeOnRemovedOrEmptyGroup() {
Group group = getModel().getGroup();
if (!group.getParent().getElements().contains(group) ||
group.getGraphs().isEmpty()) {
close();
}
SwingUtilities.invokeLater(() -> {
Group group = getModel().getGroup();
if (!group.getParent().getElements().contains(group) ||
group.getGraphs().isEmpty()) {
close();
}
});
}
public void addSelectedNodes(Collection<InputNode> nodes, boolean showIfHidden) {
@ -405,8 +417,7 @@ public final class EditorTopComponent extends TopComponent implements TopCompone
WindowManager manager = WindowManager.getDefault();
for (Mode m : manager.getModes()) {
for (TopComponent topComponent : manager.getOpenedTopComponents(m)) {
if (topComponent instanceof EditorTopComponent) {
EditorTopComponent editor = (EditorTopComponent) topComponent;
if (topComponent instanceof EditorTopComponent editor) {
editor.setBoldDisplayName(false);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2024, 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
@ -26,8 +26,6 @@ package com.sun.hotspot.igv.view;
import com.sun.hotspot.igv.data.InputGraph;
import com.sun.hotspot.igv.data.services.GraphViewer;
import com.sun.hotspot.igv.difference.Difference;
import com.sun.hotspot.igv.graph.Diagram;
import com.sun.hotspot.igv.settings.Settings;
import org.openide.util.lookup.ServiceProvider;
/**
@ -38,33 +36,37 @@ import org.openide.util.lookup.ServiceProvider;
public class GraphViewerImplementation implements GraphViewer {
@Override
public void viewDifference(InputGraph firstGraph, InputGraph secondGraph) {
public InputGraph viewDifference(InputGraph firstGraph, InputGraph secondGraph) {
if (firstGraph.getGroup() != secondGraph.getGroup()) {
InputGraph diffGraph = Difference.createDiffGraph(firstGraph, secondGraph);
view(diffGraph, true);
return view(diffGraph, true);
} else {
view(firstGraph, true);
EditorTopComponent etc = EditorTopComponent.findEditorForGraph(firstGraph);
if (etc != null) {
etc.getModel().selectDiffGraph(secondGraph);
etc.requestActive();
if (view(firstGraph, true) != null) {
EditorTopComponent etc = EditorTopComponent.findEditorForGraph(firstGraph);
if (etc != null) {
etc.getModel().selectDiffGraph(secondGraph);
etc.requestActive();
return etc.getModel().getGraph();
}
}
return null;
}
}
@Override
public void view(InputGraph graph, boolean newTab) {
public InputGraph view(InputGraph graph, boolean newTab) {
if (!newTab) {
EditorTopComponent etc = EditorTopComponent.findEditorForGraph(graph);
if (etc != null) {
etc.getModel().selectGraph(graph);
etc.requestActive();
return;
return etc.getModel().getGraph();
}
}
DiagramViewModel model = new DiagramViewModel(graph);
EditorTopComponent etc = new EditorTopComponent(model);
etc.open();
etc.requestActive();
return etc.getModel().getGraph();
}
}