diff --git a/src/utils/IdealGraphVisualizer/Coordinator/pom.xml b/src/utils/IdealGraphVisualizer/Coordinator/pom.xml index 4d773f0d8b3..fcfad0ba233 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/pom.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/pom.xml @@ -88,6 +88,11 @@ org-openide-util-lookup ${netbeans.version} + + org.netbeans.api + org-openide-modules + ${netbeans.version} + org.netbeans.api org-openide-util-ui diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java index d4764648adf..c66c40810c0 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java @@ -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 { - 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 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 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 saveContexts = new ArrayList<>(); + WindowManager manager = WindowManager.getDefault(); + for (Mode mode : manager.getModes()) { + List 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 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("" + documentPath.getFileName().toString() + ""); + setToolTipText("File: " + path); + } else { + documentPath = null; + setHtmlDisplayName("untitled"); + 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 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 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 diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/ImportAction.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/ImportAction.java index 03d062d8041..f503e6c2eb7 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/ImportAction.java +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/ImportAction.java @@ -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; diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/OpenAction.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/OpenAction.java new file mode 100644 index 00000000000..cd322efe619 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/OpenAction.java @@ -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"; + } +} diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAction.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAction.java index e1b3a62f0eb..9f2ac69aa64 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAction.java +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAction.java @@ -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"); diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAllAction.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAllAction.java index e95099d0f97..04158b23b52 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAllAction.java +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/RemoveAllAction.java @@ -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(); } } diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAllAction.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAction.java similarity index 77% rename from src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAllAction.java rename to src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAction.java index dde018f60e9..77ec88d0659 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAllAction.java +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAction.java @@ -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 diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAsAction.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAsAction.java index 4be57a51dba..65b13dfbf06 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAsAction.java +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/actions/SaveAsAction.java @@ -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; - } } diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/Bundle.properties b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/Bundle.properties index 1b17042508e..2bebc0e2797 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/Bundle.properties +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/Bundle.properties @@ -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 diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/actions/Bundle.properties b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/actions/Bundle.properties index de3aa509a31..f192e91fceb 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/actions/Bundle.properties +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/actions/Bundle.properties @@ -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... diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/import.png b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/import.png index 7e4a6badcb1..d8c8c766b88 100644 Binary files a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/import.png and b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/import.png differ diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/open.png b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/open.png new file mode 100644 index 00000000000..212763d1263 Binary files /dev/null and b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/open.png differ diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/saveall.gif b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/save_as.gif similarity index 100% rename from src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/saveall.gif rename to src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/images/save_as.gif diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml index 60e73788c95..dd1a2c0d2ab 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/resources/com/sun/hotspot/igv/coordinator/layer.xml @@ -26,8 +26,9 @@ + + - @@ -55,6 +56,10 @@ + + + + @@ -71,13 +76,13 @@ + + + + - - - - - + @@ -105,8 +110,8 @@ - + diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Folder.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Folder.java index 9ff7c32bd1f..3bd92a49cbf 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Folder.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Folder.java @@ -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 getChangedEvent(); + Properties getProperties(); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/FolderElement.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/FolderElement.java index eb0a874278f..2bf153674c7 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/FolderElement.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/FolderElement.java @@ -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 getDisplayNameChangedEvent(); void setName(String name); String getName(); String getDisplayName(); void setParent(Folder parent); Folder getParent(); + Properties getProperties(); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/GraphDocument.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/GraphDocument.java index 1f13cb3b433..4bf933d43c2 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/GraphDocument.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/GraphDocument.java @@ -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); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Group.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Group.java index 01af950a093..e98164409b6 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Group.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/Group.java @@ -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 xmlDocument = new TopElementHandler<>(); + private final TopElementHandler xmlData = new TopElementHandler<>(); private final Map differenceEncoding = new HashMap<>(); private final Map lastParsedGraph = new HashMap<>(); - private final GroupCallback groupCallback; + private final GraphDocument callbackDocument; + private final GraphContextAction contextAction; + private final ArrayList contexts = new ArrayList<>(); private final HashMap idCache = new HashMap<>(); private final ArrayList> 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; - } - - // - private ElementHandler topHandler = new ElementHandler(TOP_ELEMENT) { + // + private final ElementHandler 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; + } + }; + // + private final HandoverElementHandler bytecodesHandler = new XMLParser.HandoverElementHandler<>(BYTECODES_ELEMENT, true) { + + @Override + protected void end(String text) { + getParentObject().setBytecodes(text); + } + }; + // + private final HandoverElementHandler inlinedHandler = new XMLParser.HandoverElementHandler<>(INLINE_ELEMENT); + // + private final ElementHandler inlinedMethodHandler = new XMLParser.ElementHandler<>(METHOD_ELEMENT) { + + @Override + protected InputMethod start() throws SAXException { + InputMethod method = parseMethod(this, getParentObject().getGroup()); + getParentObject().addInlined(method); + return method; + } + }; + // + private final HandoverElementHandler nodesHandler = new HandoverElementHandler<>(NODES_ELEMENT); + // + private final HandoverElementHandler controlFlowHandler = new HandoverElementHandler<>(CONTROL_FLOW_ELEMENT); + private final HandoverElementHandler graphStatesHandler = new HandoverElementHandler<>(GRAPH_STATES_ELEMENT); + private final ElementHandler 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 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 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 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(); + } + }; + // + private final ElementHandler 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; + } + }; + // + private final HandoverElementHandler blockNodesHandler = new HandoverElementHandler<>(NODES_ELEMENT); + // + private final HandoverElementHandler successorsHandler = new HandoverElementHandler<>(SUCCESSORS_ELEMENT); + // + private final ElementHandler 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(); + } + }; + // + private final HandoverElementHandler edgesHandler = new HandoverElementHandler<>(EDGES_ELEMENT); + // + private final EdgeElementHandler edgeHandler = new EdgeElementHandler(EDGE_ELEMENT) { + + @Override + protected InputEdge start(InputEdge conn) { + InputGraph inputGraph = getParentObject(); + inputGraph.addEdge(conn); + return conn; + } + }; + // + private final EdgeElementHandler removeEdgeHandler = new EdgeElementHandler(REMOVE_EDGE_ELEMENT) { + + @Override + protected InputEdge start(InputEdge conn) { + getParentObject().removeEdge(conn); + return conn; + } + }; + // + private final HandoverElementHandler propertiesHandler = new HandoverElementHandler<>(PROPERTIES_ELEMENT); + // + private final ElementHandler 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; + // + private final ElementHandler 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(); + } + }; + // + private final ElementHandler 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; + } + }; + // + private final ElementHandler 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; + // + private final ElementHandler topHandler = new ElementHandler<>(TOP_ELEMENT) { + + @Override + protected GraphDocument start() { graphDocument = new GraphDocument(); return graphDocument; } }; // - private ElementHandler groupHandler = new XMLParser.ElementHandler(GROUP_ELEMENT) { + private final ElementHandler 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 { - } - }; - // - private ElementHandler methodHandler = new XMLParser.ElementHandler(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; - } - // - private HandoverElementHandler bytecodesHandler = new XMLParser.HandoverElementHandler(BYTECODES_ELEMENT, true) { - - @Override - protected void end(String text) throws SAXException { - getParentObject().setBytecodes(text); - } - }; - // - private HandoverElementHandler inlinedHandler = new XMLParser.HandoverElementHandler<>(INLINE_ELEMENT); - // - private ElementHandler inlinedMethodHandler = new XMLParser.ElementHandler(METHOD_ELEMENT) { - - @Override - protected InputMethod start() throws SAXException { - InputMethod method = parseMethod(this, getParentObject().getGroup()); - getParentObject().addInlined(method); - return method; + protected void end(String text) { } }; // - private ElementHandler graphHandler = new XMLParser.ElementHandler(GRAPH_ELEMENT) { + private final ElementHandler 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(); + } + }; + // + private final HandoverElementHandler 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); + } } } }; - // - private HandoverElementHandler nodesHandler = new HandoverElementHandler<>(NODES_ELEMENT); - // - private HandoverElementHandler controlFlowHandler = new HandoverElementHandler<>(CONTROL_FLOW_ELEMENT); - // - private ElementHandler 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); + 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; } - }; - // - private HandoverElementHandler blockNodesHandler = new HandoverElementHandler<>(NODES_ELEMENT); - // - private ElementHandler blockNodeHandler = new ElementHandler(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"); } - }; - // - private HandoverElementHandler successorsHandler = new HandoverElementHandler<>(SUCCESSORS_ELEMENT); - // - private ElementHandler 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(); - } - }; - // - private ElementHandler nodeHandler = new ElementHandler(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; - } - }; - // - private ElementHandler removeNodeHandler = new ElementHandler(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); } - }; - // - private HandoverElementHandler edgesHandler = new HandoverElementHandler<>(EDGES_ELEMENT); + } // Local class for edge elements private class EdgeElementHandler extends ElementHandler { @@ -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; } } - // - private EdgeElementHandler edgeHandler = new EdgeElementHandler(EDGE_ELEMENT) { - - @Override - protected InputEdge start(InputEdge conn) throws SAXException { - getParentObject().addEdge(conn); - return conn; - } - }; - // - private EdgeElementHandler removeEdgeHandler = new EdgeElementHandler(REMOVE_EDGE_ELEMENT) { - - @Override - protected InputEdge start(InputEdge conn) throws SAXException { - getParentObject().removeEdge(conn); - return conn; - } - }; - // - private HandoverElementHandler propertiesHandler = new HandoverElementHandler<>(PROPERTIES_ELEMENT); - // - private HandoverElementHandler groupPropertiesHandler = new HandoverElementHandler(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(); - } - } - } - }; - // - private ElementHandler 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()); - } - }; - - 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); - } - } } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java index eb3f1451703..f930e478776 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java @@ -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 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 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 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 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 contexts) throws IOException { + List 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 visibleNodes, AtomicBoolean showAll) { } + + public interface GraphContextAction { + void performAction(GraphContext context); + } } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/GraphViewer.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/GraphViewer.java index ebaa03df282..3cef9c4fc95 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/GraphViewer.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/GraphViewer.java @@ -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); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/GroupCallback.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/GroupCallback.java deleted file mode 100644 index b35f3eabf89..00000000000 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/GroupCallback.java +++ /dev/null @@ -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); -} diff --git a/src/utils/IdealGraphVisualizer/Data/src/test/java/com/sun/hotspot/igv/data/serialization/ParserTest.java b/src/utils/IdealGraphVisualizer/Data/src/test/java/com/sun/hotspot/igv/data/serialization/ParserTest.java index 43426046448..9788ee4443c 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/test/java/com/sun/hotspot/igv/data/serialization/ParserTest.java +++ b/src/utils/IdealGraphVisualizer/Data/src/test/java/com/sun/hotspot/igv/data/serialization/ParserTest.java @@ -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()); } diff --git a/src/utils/IdealGraphVisualizer/NetworkConnection/src/main/java/com/sun/hotspot/igv/connection/Client.java b/src/utils/IdealGraphVisualizer/NetworkConnection/src/main/java/com/sun/hotspot/igv/connection/Client.java deleted file mode 100644 index 2f4b6cff0db..00000000000 --- a/src/utils/IdealGraphVisualizer/NetworkConnection/src/main/java/com/sun/hotspot/igv/connection/Client.java +++ /dev/null @@ -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); - } - } - } -} diff --git a/src/utils/IdealGraphVisualizer/NetworkConnection/src/main/java/com/sun/hotspot/igv/connection/Server.java b/src/utils/IdealGraphVisualizer/NetworkConnection/src/main/java/com/sun/hotspot/igv/connection/Server.java index 523f4d2017d..a507c568be2 100644 --- a/src/utils/IdealGraphVisualizer/NetworkConnection/src/main/java/com/sun/hotspot/igv/connection/Server.java +++ b/src/utils/IdealGraphVisualizer/NetworkConnection/src/main/java/com/sun/hotspot/igv/connection/Server.java @@ -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(); + } } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java index 23cd4a4360f..e47518de4a7 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java @@ -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 diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java index f48e05ec6b9..6d7599e6d34 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java @@ -332,6 +332,14 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene final HashSet allNodes = new HashSet<>(getGroup().getAllNodes()); allNodes.removeAll(nodes); setHiddenNodes(allNodes); + + + } + + public Set getVisibleNodes() { + final Set visibleNodes = new HashSet<>(getGraph().getNodesAsSet()); + visibleNodes.removeAll(hiddenNodes); + return visibleNodes; } public void setHiddenNodes(Set nodes) { diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java index 57d2b006ac0..617f59a591d 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java @@ -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 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); } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/GraphViewerImplementation.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/GraphViewerImplementation.java index d4b88135408..04e63ebbc5f 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/GraphViewerImplementation.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/GraphViewerImplementation.java @@ -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(); } }