/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.view;
import com.sun.hotspot.igv.data.ChangedEvent;
import com.sun.hotspot.igv.data.ChangedListener;
import com.sun.hotspot.igv.data.InputNode;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.data.Properties.PropertyMatcher;
import com.sun.hotspot.igv.data.services.InputGraphProvider;
import com.sun.hotspot.igv.filter.FilterChain;
import com.sun.hotspot.igv.filter.FilterChainProvider;
import com.sun.hotspot.igv.graph.Diagram;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.services.DiagramProvider;
import com.sun.hotspot.igv.svg.BatikSVG;
import com.sun.hotspot.igv.util.LookupHistory;
import com.sun.hotspot.igv.util.RangeSlider;
import com.sun.hotspot.igv.view.actions.*;
import java.awt.*;
import java.awt.event.HierarchyBoundsListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.util.List;
import java.util.*;
import javax.swing.*;
import javax.swing.border.Border;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.actions.RedoAction;
import org.openide.actions.UndoAction;
import org.openide.awt.Toolbar;
import org.openide.awt.ToolbarPool;
import org.openide.awt.UndoRedo;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.util.lookup.ProxyLookup;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
/**
*
* @author Thomas Wuerthinger
*/
public final class EditorTopComponent extends TopComponent implements PropertyChangeListener {
private DiagramViewer scene;
private InstanceContent content;
private InstanceContent graphContent;
private EnableBlockLayoutAction blockLayoutAction;
private OverviewAction overviewAction;
private HideDuplicatesAction hideDuplicatesAction;
private PredSuccAction predSuccAction;
private SelectionModeAction selectionModeAction;
private PanModeAction panModeAction;
private boolean notFirstTime;
private JComponent satelliteComponent;
private JPanel centerPanel;
private CardLayout cardLayout;
private RangeSlider rangeSlider;
private JToggleButton overviewButton;
private JToggleButton hideDuplicatesButton;
private static final String PREFERRED_ID = "EditorTopComponent";
private static final String SATELLITE_STRING = "satellite";
private static final String SCENE_STRING = "scene";
private DiagramViewModel rangeSliderModel;
private ExportCookie exportCookie = new ExportCookie() {
@Override
public void export(File f) {
Graphics2D svgGenerator = BatikSVG.createGraphicsObject();
if (svgGenerator == null) {
NotifyDescriptor message = new NotifyDescriptor.Message("For export to SVG files the Batik SVG Toolkit must be intalled.", NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notifyLater(message);
} else {
scene.paint(svgGenerator);
FileOutputStream os = null;
try {
os = new FileOutputStream(f);
Writer out = new OutputStreamWriter(os, "UTF-8");
BatikSVG.printToStream(svgGenerator, out, true);
} catch (FileNotFoundException e) {
NotifyDescriptor message = new NotifyDescriptor.Message("For export to SVG files the Batik SVG Toolkit must be intalled.", NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notifyLater(message);
} catch (UnsupportedEncodingException e) {
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
}
}
}
}
}
};
private DiagramProvider diagramProvider = new DiagramProvider() {
@Override
public Diagram getDiagram() {
return getModel().getDiagramToView();
}
@Override
public ChangedEvent<DiagramProvider> getChangedEvent() {
return diagramChangedEvent;
}
};
private ChangedEvent<DiagramProvider> diagramChangedEvent = new ChangedEvent<>(diagramProvider);
private void updateDisplayName() {
setDisplayName(getDiagram().getName());
setToolTipText(getDiagram().getGraph().getGroup().getName());
}
public EditorTopComponent(Diagram diagram) {
LookupHistory.init(InputGraphProvider.class);
LookupHistory.init(DiagramProvider.class);
this.setFocusable(true);
FilterChain filterChain = null;
FilterChain sequence = null;
FilterChainProvider provider = Lookup.getDefault().lookup(FilterChainProvider.class);
if (provider == null) {
filterChain = new FilterChain();
sequence = new FilterChain();
} else {
filterChain = provider.getFilterChain();
sequence = provider.getSequence();
}
setName(NbBundle.getMessage(EditorTopComponent.class, "CTL_EditorTopComponent"));
setToolTipText(NbBundle.getMessage(EditorTopComponent.class, "HINT_EditorTopComponent"));
Action[] actions = new Action[]{
PrevDiagramAction.get(PrevDiagramAction.class),
NextDiagramAction.get(NextDiagramAction.class),
null,
ExtractAction.get(ExtractAction.class),
ShowAllAction.get(HideAction.class),
ShowAllAction.get(ShowAllAction.class),
null,
ZoomInAction.get(ZoomInAction.class),
ZoomOutAction.get(ZoomOutAction.class),
};
Action[] actionsWithSelection = new Action[]{
ExtractAction.get(ExtractAction.class),
ShowAllAction.get(HideAction.class),
null,
ExpandPredecessorsAction.get(ExpandPredecessorsAction.class),
ExpandSuccessorsAction.get(ExpandSuccessorsAction.class)
};
initComponents();
ToolbarPool.getDefault().setPreferredIconSize(16);
Toolbar toolBar = new Toolbar();
Border b = (Border) UIManager.get("Nb.Editor.Toolbar.border"); //NOI18N
toolBar.setBorder(b);
JPanel container = new JPanel();
this.add(container, BorderLayout.NORTH);
container.setLayout(new BorderLayout());
container.add(BorderLayout.NORTH, toolBar);
rangeSliderModel = new DiagramViewModel(diagram.getGraph().getGroup(), filterChain, sequence);
rangeSlider = new RangeSlider();
rangeSlider.setModel(rangeSliderModel);
JScrollPane pane = new JScrollPane(rangeSlider, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
container.add(BorderLayout.CENTER, pane);
scene = new DiagramScene(actions, actionsWithSelection, rangeSliderModel);
content = new InstanceContent();
graphContent = new InstanceContent();
this.associateLookup(new ProxyLookup(new Lookup[]{scene.getLookup(), new AbstractLookup(graphContent), new AbstractLookup(content)}));
content.add(exportCookie);
content.add(rangeSliderModel);
content.add(diagramProvider);
rangeSliderModel.getDiagramChangedEvent().addListener(diagramChangedListener);
rangeSliderModel.selectGraph(diagram.getGraph());
rangeSliderModel.getViewPropertiesChangedEvent().addListener(new ChangedListener<DiagramViewModel>() {
@Override
public void changed(DiagramViewModel source) {
hideDuplicatesButton.setSelected(getModel().getHideDuplicates());
hideDuplicatesAction.setState(getModel().getHideDuplicates());
}
});
toolBar.add(NextDiagramAction.get(NextDiagramAction.class));
toolBar.add(PrevDiagramAction.get(PrevDiagramAction.class));
toolBar.addSeparator();
toolBar.add(ExtractAction.get(ExtractAction.class));
toolBar.add(ShowAllAction.get(HideAction.class));
toolBar.add(ShowAllAction.get(ShowAllAction.class));
toolBar.addSeparator();
toolBar.add(ShowAllAction.get(ZoomInAction.class));
toolBar.add(ShowAllAction.get(ZoomOutAction.class));
blockLayoutAction = new EnableBlockLayoutAction();
JToggleButton button = new JToggleButton(blockLayoutAction);
button.setSelected(false);
toolBar.add(button);
blockLayoutAction.addPropertyChangeListener(this);
overviewAction = new OverviewAction();
overviewButton = new JToggleButton(overviewAction);
overviewButton.setSelected(false);
toolBar.add(overviewButton);
overviewAction.addPropertyChangeListener(this);
predSuccAction = new PredSuccAction();
button = new JToggleButton(predSuccAction);
button.setSelected(true);
toolBar.add(button);
predSuccAction.addPropertyChangeListener(this);
hideDuplicatesAction = new HideDuplicatesAction();
hideDuplicatesButton = new JToggleButton(hideDuplicatesAction);
hideDuplicatesButton.setSelected(false);
toolBar.add(hideDuplicatesButton);
hideDuplicatesAction.addPropertyChangeListener(this);
toolBar.addSeparator();
toolBar.add(UndoAction.get(UndoAction.class));
toolBar.add(RedoAction.get(RedoAction.class));
toolBar.addSeparator();
ButtonGroup interactionButtons = new ButtonGroup();
panModeAction = new PanModeAction();
panModeAction.setSelected(true);
button = new JToggleButton(panModeAction);
button.setSelected(true);
interactionButtons.add(button);
toolBar.add(button);
panModeAction.addPropertyChangeListener(this);
selectionModeAction = new SelectionModeAction();
button = new JToggleButton(selectionModeAction);
interactionButtons.add(button);
toolBar.add(button);
selectionModeAction.addPropertyChangeListener(this);
toolBar.add(Box.createHorizontalGlue());
Action action = Utilities.actionsForPath("QuickSearchShadow").get(0);
Component quicksearch = ((Presenter.Toolbar) action).getToolbarPresenter();
try {
// (aw) workaround for disappearing search bar due to reparenting one shared component instance.
quicksearch = (Component) quicksearch.getClass().getConstructor(KeyStroke.class).newInstance(new Object[]{null});
} catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
}
Dimension preferredSize = quicksearch.getPreferredSize();
preferredSize = new Dimension((int) preferredSize.getWidth() * 2, (int) preferredSize.getHeight());
quicksearch.setMinimumSize(preferredSize); // necessary for GTK LAF
quicksearch.setPreferredSize(preferredSize);
toolBar.add(quicksearch);
centerPanel = new JPanel();
this.add(centerPanel, BorderLayout.CENTER);
cardLayout = new CardLayout();
centerPanel.setLayout(cardLayout);
centerPanel.add(SCENE_STRING, scene.getComponent());
centerPanel.setBackground(Color.WHITE);
satelliteComponent = scene.createSatelliteView();
satelliteComponent.setSize(200, 200);
centerPanel.add(SATELLITE_STRING, satelliteComponent);
// TODO: Fix the hot key for entering the satellite view
this.addKeyListener(keyListener);
scene.getComponent().addHierarchyBoundsListener(new HierarchyBoundsListener() {
@Override
public void ancestorMoved(HierarchyEvent e) {
}
@Override
public void ancestorResized(HierarchyEvent e) {
if (!notFirstTime && scene.getComponent().getBounds().width > 0) {
notFirstTime = true;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
EditorTopComponent.this.scene.initialize();
}
});
}
}
});
if (diagram.getGraph().getGroup().getGraphsCount() == 1) {
rangeSlider.setVisible(false);
}
updateDisplayName();
}
private KeyListener keyListener = new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_S) {
EditorTopComponent.this.overviewButton.setSelected(true);
EditorTopComponent.this.overviewAction.setState(true);
}
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_S) {
EditorTopComponent.this.overviewButton.setSelected(false);
EditorTopComponent.this.overviewAction.setState(false);
}
}
};
public DiagramViewModel getDiagramModel() {
return rangeSliderModel;
}
private void showSatellite() {
cardLayout.show(centerPanel, SATELLITE_STRING);
satelliteComponent.requestFocus();
}
private void showScene() {
cardLayout.show(centerPanel, SCENE_STRING);
scene.getComponent().requestFocus();
}
public void zoomOut() {
scene.zoomOut();
}
public void zoomIn() {
scene.zoomIn();
}
public void showPrevDiagram() {
int fp = getModel().getFirstPosition();
int sp = getModel().getSecondPosition();
if (fp != 0) {
fp--;
sp--;
getModel().setPositions(fp, sp);
}
}
public DiagramViewModel getModel() {
return rangeSliderModel;
}
public FilterChain getFilterChain() {
return getModel().getFilterChain();
}
public static EditorTopComponent getActive() {
Set<? extends Mode> modes = WindowManager.getDefault().getModes();
for (Mode m : modes) {
TopComponent tc = m.getSelectedTopComponent();
if (tc instanceof EditorTopComponent) {
return (EditorTopComponent) tc;
}
}
return null;
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents() {
jCheckBox1 = new javax.swing.JCheckBox();
org.openide.awt.Mnemonics.setLocalizedText(jCheckBox1, "jCheckBox1");
jCheckBox1.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
jCheckBox1.setMargin(new java.awt.Insets(0, 0, 0, 0));
setLayout(new java.awt.BorderLayout());
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox jCheckBox1;
// End of variables declaration//GEN-END:variables
@Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_NEVER;
}
@Override
public void componentOpened() {
}
@Override
public void componentClosed() {
rangeSliderModel.close();
}
@Override
protected String preferredID() {
return PREFERRED_ID;
}
private ChangedListener<DiagramViewModel> diagramChangedListener = new ChangedListener<DiagramViewModel>() {
@Override
public void changed(DiagramViewModel source) {
updateDisplayName();
Collection<Object> list = new ArrayList<>();
list.add(new EditorInputGraphProvider(EditorTopComponent.this));
graphContent.set(list, null);
diagramProvider.getChangedEvent().fire();
}
};
public boolean showPredSucc() {
return (Boolean) predSuccAction.getValue(PredSuccAction.STATE);
}
public void setSelection(PropertyMatcher matcher) {
Properties.PropertySelector<Figure> selector = new Properties.PropertySelector<>(getModel().getDiagramToView().getFigures());
List<Figure> list = selector.selectMultiple(matcher);
setSelectedFigures(list);
}
public void setSelectedFigures(List<Figure> list) {
scene.setSelection(list);
scene.centerFigures(list);
}
public void setSelectedNodes(Set<InputNode> nodes) {
List<Figure> list = new ArrayList<>();
Set<Integer> ids = new HashSet<>();
for (InputNode n : nodes) {
ids.add(n.getId());
}
for (Figure f : getModel().getDiagramToView().getFigures()) {
for (InputNode n : f.getSource().getSourceNodes()) {
if (ids.contains(n.getId())) {
list.add(f);
break;
}
}
}
setSelectedFigures(list);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getSource() == this.predSuccAction) {
boolean b = (Boolean) predSuccAction.getValue(PredSuccAction.STATE);
this.getModel().setShowNodeHull(b);
} else if (evt.getSource() == this.overviewAction) {
boolean b = (Boolean) overviewAction.getValue(OverviewAction.STATE);
if (b) {
showSatellite();
} else {
showScene();
}
} else if (evt.getSource() == this.blockLayoutAction) {
boolean b = (Boolean) blockLayoutAction.getValue(EnableBlockLayoutAction.STATE);
this.getModel().setShowBlocks(b);
} else if (evt.getSource() == this.hideDuplicatesAction) {
boolean b = (Boolean) hideDuplicatesAction.getValue(HideDuplicatesAction.STATE);
this.getModel().setHideDuplicates(b);
} else if (evt.getSource() == this.selectionModeAction || evt.getSource() == this.panModeAction) {
if (panModeAction.isSelected()) {
scene.setInteractionMode(DiagramViewer.InteractionMode.PANNING);
} else if (selectionModeAction.isSelected()) {
scene.setInteractionMode(DiagramViewer.InteractionMode.SELECTION);
}
} else {
assert false : "Unknown event source";
}
}
public void extract() {
getModel().showOnly(getModel().getSelectedNodes());
}
public void hideNodes() {
Set<Integer> selectedNodes = this.getModel().getSelectedNodes();
HashSet<Integer> nodes = new HashSet<>(getModel().getHiddenNodes());
nodes.addAll(selectedNodes);
/**代码未完, 请加载全部代码(NowJava.com).**/