8302644: IGV: Apply filters per graph tab and not globally

Reviewed-by: rcastanedalo, chagedorn, thartmann
This commit is contained in:
Tobias Holenstein 2023-03-30 08:12:10 +00:00
parent f0dba218ac
commit 2c38e67b29
17 changed files with 542 additions and 558 deletions

View File

@ -40,7 +40,7 @@ public class CustomFilter extends AbstractFilter {
private String code;
private String name;
private ScriptEngine engine;
private final ScriptEngine engine;
public CustomFilter(String name, String code, ScriptEngine engine) {
this.name = name;
@ -60,31 +60,25 @@ public class CustomFilter extends AbstractFilter {
public void setName(String s) {
name = s;
fireChangedEvent();
}
public void setCode(String s) {
code = s;
fireChangedEvent();
}
@Override
public OpenCookie getEditor() {
return new OpenCookie() {
@Override
public void open() {
openInEditor();
}
};
return this::openInEditor;
}
public boolean openInEditor() {
EditFilterDialog dialog = new EditFilterDialog(CustomFilter.this);
dialog.setVisible(true);
boolean result = dialog.wasAccepted();
this.getChangedEvent().fire();
return result;
boolean accepted = dialog.wasAccepted();
if (accepted) {
getChangedEvent().fire();
}
return accepted;
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@ -29,6 +29,7 @@ import com.sun.hotspot.igv.data.ChangedListener;
import com.sun.hotspot.igv.graph.Diagram;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
@ -37,24 +38,29 @@ import java.util.List;
*/
public class FilterChain implements ChangedEventProvider<FilterChain> {
private List<Filter> filters;
private transient ChangedEvent<FilterChain> changedEvent;
private final List<Filter> filters;
private final transient ChangedEvent<FilterChain> changedEvent;
private final String name;
private ChangedListener<Filter> changedListener = new ChangedListener<Filter>() {
private final ChangedListener<Filter> changedListener = new ChangedListener<Filter>() {
@Override
public void changed(Filter source) {
changedEvent.fire();
}
};
public FilterChain() {
public FilterChain(String name) {
this.name = name;
filters = new ArrayList<>();
changedEvent = new ChangedEvent<>(this);
}
public FilterChain(FilterChain f) {
this.filters = new ArrayList<>(f.filters);
changedEvent = new ChangedEvent<>(this);
public FilterChain() {
this("");
}
public void sortBy(List<String> order) {
filters.sort(Comparator.comparingInt(f -> order.indexOf(f.getName())));
}
@Override
@ -62,35 +68,14 @@ public class FilterChain implements ChangedEventProvider<FilterChain> {
return changedEvent;
}
public Filter getFilterAt(int index) {
assert index >= 0 && index < filters.size();
return filters.get(index);
}
public void apply(Diagram d) {
for (Filter f : filters) {
f.apply(d);
}
}
public void apply(Diagram d, FilterChain sequence) {
List<Filter> applied = new ArrayList<>();
for (Filter f : sequence.getFilters()) {
if (filters.contains(f)) {
f.apply(d);
applied.add(f);
}
}
for (Filter f : filters) {
if (!applied.contains(f)) {
f.apply(d);
public void applyInOrder(Diagram diagram, FilterChain filterOrder) {
for (Filter filter : filterOrder.getFilters()) {
if (filters.contains(filter)) {
filter.apply(diagram);
}
}
}
public void addFilter(Filter filter) {
assert filter != null;
filters.add(filter);
@ -102,6 +87,14 @@ public class FilterChain implements ChangedEventProvider<FilterChain> {
return filters.contains(filter);
}
public void clearFilters() {
for (Filter filter : filters) {
filter.getChangedEvent().removeListener(changedListener);
}
filters.clear();
changedEvent.fire();
}
public void removeFilter(Filter filter) {
assert filters.contains(filter);
filters.remove(filter);
@ -129,7 +122,22 @@ public class FilterChain implements ChangedEventProvider<FilterChain> {
changedEvent.fire();
}
public void addFilters(List<Filter> filtersToAdd) {
for (Filter filter : filtersToAdd) {
addFilter(filter);
}
}
public List<Filter> getFilters() {
return Collections.unmodifiableList(filters);
}
public String getName() {
return name;
}
@Override
public String toString() {
return getName();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,13 +23,23 @@
*/
package com.sun.hotspot.igv.filter;
import com.sun.hotspot.igv.data.ChangedListener;
import javax.swing.JComboBox;
/**
*
* @author Thomas Wuerthinger
*/
public interface FilterChainProvider {
public FilterChain getFilterChain();
FilterChain getFilterChain();
FilterChain getAllFiltersOrdered();
public FilterChain getSequence();
FilterChain createNewCustomFilterChain();
void setCustomFilterChain(FilterChain filterChain);
void selectFilterChain(FilterChain filterChain);
void setFilterChainSelectionChangedListener(ChangedListener<JComboBox<FilterChain>> listener);
}

View File

@ -1,82 +0,0 @@
/*
* Copyright (c) 2008, 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.
*
* 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.filter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author Thomas Wuerthinger
*/
public class FilterSetting {
private Set<Filter> filters;
private String name;
public FilterSetting() {
this(null);
}
public FilterSetting(String name) {
this.name = name;
filters = new HashSet<>();
}
public Set<Filter> getFilters() {
return Collections.unmodifiableSet(filters);
}
public void addFilter(Filter f) {
assert !filters.contains(f);
filters.add(f);
}
public void removeFilter(Filter f) {
assert filters.contains(f);
filters.remove(f);
}
public boolean containsFilter(Filter f) {
return filters.contains(f);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getFilterCount() {
return filters.size();
}
@Override
public String toString() {
return getName();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,8 +23,10 @@
*/
package com.sun.hotspot.igv.filterwindow;
import com.sun.hotspot.igv.data.ChangedListener;
import com.sun.hotspot.igv.filter.FilterChain;
import com.sun.hotspot.igv.filter.FilterChainProvider;
import javax.swing.JComboBox;
import org.openide.util.lookup.ServiceProvider;
/**
@ -36,11 +38,31 @@ public class FilterChainProviderImplementation implements FilterChainProvider {
@Override
public FilterChain getFilterChain() {
return FilterTopComponent.findInstance().getFilterChain();
return FilterTopComponent.findInstance().getCurrentChain();
}
@Override
public FilterChain getSequence() {
return FilterTopComponent.findInstance().getSequence();
public FilterChain getAllFiltersOrdered() {
return FilterTopComponent.findInstance().getAllFiltersOrdered();
}
@Override
public FilterChain createNewCustomFilterChain() {
return FilterTopComponent.findInstance().createNewCustomFilterChain();
}
@Override
public void selectFilterChain(FilterChain filterChain) {
FilterTopComponent.findInstance().selectFilterChain(filterChain);
}
@Override
public void setCustomFilterChain(FilterChain filterChain) {
FilterTopComponent.findInstance().setCustomFilterChain(filterChain);
}
@Override
public void setFilterChainSelectionChangedListener(ChangedListener<JComboBox<FilterChain>> listener) {
FilterTopComponent.findInstance().setFilterChainSelectionChangedListener(listener);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@ -45,10 +45,9 @@ import org.openide.util.lookup.InstanceContent;
*
* @author Thomas Wuerthinger
*/
public class FilterNode extends CheckNode implements LookupListener, ChangedListener<FilterTopComponent> {
public class FilterNode extends CheckNode implements ChangedListener<FilterTopComponent> {
private Filter filter;
private Lookup.Result<FilterChain> result;
private final Filter filter;
public FilterNode(Filter filter) {
this(filter, new InstanceContent());
@ -64,12 +63,8 @@ public class FilterNode extends CheckNode implements LookupListener, ChangedList
update();
Lookup.Template<FilterChain> tpl = new Lookup.Template<>(FilterChain.class);
result = Utilities.actionsGlobalContext().lookup(tpl);
result.addLookupListener(this);
FilterTopComponent.findInstance().getFilterSettingsChangedEvent().addListener(this);
resultChanged(null);
changed(FilterTopComponent.findInstance());
setShortDescription("Double-click to open filter");
}
@ -99,13 +94,8 @@ public class FilterNode extends CheckNode implements LookupListener, ChangedList
return OpenAction.get(OpenAction.class).createContextAwareInstance(Utilities.actionsGlobalContext());
}
@Override
public void resultChanged(LookupEvent lookupEvent) {
changed(FilterTopComponent.findInstance());
}
@Override
public void changed(FilterTopComponent source) {
setSelected(source.getFilterChain().containsFilter(filter));
setSelected(source.getCurrentChain().containsFilter(filter));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,11 +28,11 @@ import com.sun.hotspot.igv.data.ChangedListener;
import com.sun.hotspot.igv.filter.CustomFilter;
import com.sun.hotspot.igv.filter.Filter;
import com.sun.hotspot.igv.filter.FilterChain;
import com.sun.hotspot.igv.filter.FilterSetting;
import com.sun.hotspot.igv.filterwindow.actions.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.*;
@ -42,8 +42,7 @@ import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JComboBox;
import javax.swing.UIManager;
import javax.swing.*;
import javax.swing.border.Border;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;
@ -67,7 +66,7 @@ import org.openide.windows.WindowManager;
*
* @author Thomas Wuerthinger
*/
public final class FilterTopComponent extends TopComponent implements LookupListener, ExplorerManager.Provider {
public final class FilterTopComponent extends TopComponent implements ExplorerManager.Provider {
private static FilterTopComponent instance;
public static final String FOLDER_ID = "Filters";
@ -75,101 +74,158 @@ public final class FilterTopComponent extends TopComponent implements LookupList
public static final String ENABLED_ID = "enabled";
public static final String PREFERRED_ID = "FilterTopComponent";
public static final String JAVASCRIPT_HELPER_ID = "JavaScriptHelper";
private CheckListView view;
private ExplorerManager manager;
private FilterChain filterChain;
private FilterChain sequence;
private ScriptEngine engine;
private Lookup.Result<FilterChain> result;
private JComboBox comboBox;
private List<FilterSetting> filterSettings;
private FilterSetting customFilterSetting = new FilterSetting("-- Custom --");
private ChangedEvent<FilterTopComponent> filterSettingsChangedEvent;
private ActionListener comboBoxActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
comboBoxSelectionChanged();
}
private final CheckListView view;
private final ExplorerManager manager;
private final ScriptEngine engine;
private final JComboBox<FilterChain> comboBox;
private final FilterChain allFiltersOrdered = new FilterChain();
private static final FilterChain defaultFilterChain = new FilterChain("DEFAULT");
private FilterChain customFilterChain;
private final ChangedEvent<FilterTopComponent> filterSettingsChangedEvent = new ChangedEvent<>(this);
private ChangedEvent<JComboBox<FilterChain>> filterChainSelectionChangedEvent;
private final ActionListener comboBoxSelectionChangedListener = l -> {
comboBoxSelectionChanged();
// notify model that user selected a different filter profile
filterChainSelectionChangedEvent.fire();
};
private static final String CUSTOM_LABEL = "--Local--";
private static final String GLOBAL_LABEL = "--Global--";
public FilterChain createNewCustomFilterChain() {
FilterChain newCustomFilterChain = new FilterChain(CUSTOM_LABEL);
newCustomFilterChain.addFilters(customFilterChain.getFilters());
return newCustomFilterChain;
}
static class CustomCellRenderer extends DefaultListCellRenderer {
public CustomCellRenderer() {
setOpaque(true);
}
public Component getListCellRendererComponent(JList jc, Object val, int idx,
boolean isSelected, boolean cellHasFocus) {
setText(" " + val.toString());
if (idx == 0) {
setForeground(Color.GRAY);
} else {
setForeground(Color.BLACK);
}
if (isSelected) {
setBackground(Color.LIGHT_GRAY);
} else {
setBackground(Color.WHITE);
}
return this;
}
}
private FilterTopComponent() {
initComponents();
setName(NbBundle.getMessage(FilterTopComponent.class, "CTL_FilterTopComponent"));
setToolTipText(NbBundle.getMessage(FilterTopComponent.class, "HINT_FilterTopComponent"));
ScriptEngineManager sem = new ScriptEngineManager();
engine = sem.getEngineByName("ECMAScript");
try {
engine.eval(getJsHelperText());
} catch (ScriptException ex) {
Exceptions.printStackTrace(ex);
}
engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("IO", System.out);
initFilters();
comboBox = new JComboBox<>();
comboBox.setRenderer(new CustomCellRenderer());
customFilterChain = new FilterChain(CUSTOM_LABEL);
customFilterChain.addFilters(defaultFilterChain.getFilters());
comboBox.addItem(customFilterChain);
FilterChain globalFilterChain = new FilterChain(GLOBAL_LABEL);
globalFilterChain.addFilters(defaultFilterChain.getFilters());
comboBox.addItem(globalFilterChain);
comboBox.setSelectedItem(globalFilterChain);
filterChainSelectionChangedEvent = new ChangedEvent<>(comboBox);
manager = new ExplorerManager();
manager.setRootContext(new AbstractNode(new FilterChildren()));
associateLookup(ExplorerUtils.createLookup(manager, getActionMap()));
view = new CheckListView();
ToolbarPool.getDefault().setPreferredIconSize(16);
Toolbar toolBar = new Toolbar();
toolBar.setBorder((Border) UIManager.get("Nb.Editor.Toolbar.border")); //NOI18N
toolBar.setMinimumSize(new Dimension(0,0)); // MacOS BUG with ToolbarWithOverflow
toolBar.add(comboBox);
this.add(toolBar, BorderLayout.NORTH);
toolBar.add(SaveFilterSettingsAction.get(SaveFilterSettingsAction.class));
toolBar.add(RemoveFilterSettingsAction.get(RemoveFilterSettingsAction.class));
toolBar.addSeparator();
toolBar.add(NewFilterAction.get(NewFilterAction.class));
toolBar.add(RemoveFilterAction.get(RemoveFilterAction.class).createContextAwareInstance(this.getLookup()));
toolBar.add(MoveFilterUpAction.get(MoveFilterUpAction.class).createContextAwareInstance(this.getLookup()));
toolBar.add(MoveFilterDownAction.get(MoveFilterDownAction.class).createContextAwareInstance(this.getLookup()));
this.add(view, BorderLayout.CENTER);
comboBox.addActionListener(comboBoxSelectionChangedListener);
comboBoxSelectionChanged();
}
public ChangedEvent<FilterTopComponent> getFilterSettingsChangedEvent() {
return filterSettingsChangedEvent;
}
public FilterChain getSequence() {
return sequence;
public void setFilterChainSelectionChangedListener(ChangedListener<JComboBox<FilterChain>> listener) {
filterChainSelectionChangedEvent = new ChangedEvent<>(comboBox);
filterChainSelectionChangedEvent.addListener(listener);
}
public void updateSelection() {
Node[] nodes = this.getExplorerManager().getSelectedNodes();
int[] arr = new int[nodes.length];
for (int i = 0; i < nodes.length; i++) {
int index = sequence.getFilters().indexOf(((FilterNode) nodes[i]).getFilter());
arr[i] = index;
public FilterChain getAllFiltersOrdered() {
return allFiltersOrdered;
}
public FilterChain getCurrentChain() {
return (FilterChain) comboBox.getSelectedItem();
}
public void selectFilterChain(FilterChain filterChain) {
comboBox.removeActionListener(comboBoxSelectionChangedListener);
comboBox.setSelectedItem(filterChain);
if (comboBox.getSelectedIndex() < 0) {
comboBox.setSelectedIndex(0);
}
view.showSelection(arr);
comboBox.addActionListener(comboBoxSelectionChangedListener);
comboBoxSelectionChanged();
}
public void setCustomFilterChain(FilterChain filterChain) {
comboBox.removeActionListener(comboBoxSelectionChangedListener);
comboBox.removeItem(customFilterChain);
customFilterChain = filterChain;
comboBox.insertItemAt(customFilterChain, 0);
comboBox.addActionListener(comboBoxSelectionChangedListener);
}
private void comboBoxSelectionChanged() {
Object o = comboBox.getSelectedItem();
if (o == null) {
return;
FilterChain currentChain = getCurrentChain();
if (currentChain != null) {
filterSettingsChangedEvent.fire(); // notify all FilterNodes to update checkbox selection
SystemAction.get(RemoveFilterSettingsAction.class).setEnabled(currentChain != customFilterChain);
SystemAction.get(SaveFilterSettingsAction.class).setEnabled(true);
}
assert o instanceof FilterSetting;
FilterSetting s = (FilterSetting) o;
if (s != customFilterSetting) {
FilterChain chain = getFilterChain();
chain.getChangedEvent().beginAtomic();
List<Filter> toRemove = new ArrayList<>();
for (Filter f : chain.getFilters()) {
if (!s.containsFilter(f)) {
toRemove.add(f);
}
}
for (Filter f : toRemove) {
chain.removeFilter(f);
}
for (Filter f : s.getFilters()) {
if (!chain.containsFilter(f)) {
chain.addFilter(f);
}
}
chain.getChangedEvent().endAtomic();
filterSettingsChangedEvent.fire();
} else {
this.updateComboBoxSelection();
}
SystemAction.get(RemoveFilterSettingsAction.class).setEnabled(comboBox.getSelectedItem() != this.customFilterSetting);
SystemAction.get(SaveFilterSettingsAction.class).setEnabled(comboBox.getSelectedItem() == this.customFilterSetting);
}
private void updateComboBox() {
comboBox.removeAllItems();
comboBox.addItem(customFilterSetting);
for (FilterSetting s : filterSettings) {
comboBox.addItem(s);
}
this.updateComboBoxSelection();
}
public void addFilterSetting() {
NotifyDescriptor.InputLine l = new NotifyDescriptor.InputLine("Name of the new profile:", "Filter Profile");
if (DialogDisplayer.getDefault().notify(l) == NotifyDescriptor.OK_OPTION) {
String name = l.getInputText();
FilterSetting toRemove = null;
for (FilterSetting s : filterSettings) {
for (int i=0; i<comboBox.getItemCount(); i++) {
FilterChain s = comboBox.getItemAt(i);
if (s.getName().equals(name)) {
NotifyDescriptor.Confirmation conf = new NotifyDescriptor.Confirmation("Filter profile \"" + name + "\" already exists, do you want to replace it?", "Filter");
if (DialogDisplayer.getDefault().notify(conf) == NotifyDescriptor.YES_OPTION) {
toRemove = s;
comboBox.removeItem(s);
break;
} else {
return;
@ -177,77 +233,30 @@ public final class FilterTopComponent extends TopComponent implements LookupList
}
}
if (toRemove != null) {
filterSettings.remove(toRemove);
FilterChain setting = new FilterChain(name);
FilterChain chain = getCurrentChain();
for (Filter f : chain.getFilters()) {
setting.addFilter(f);
}
FilterSetting setting = createFilterSetting(name);
filterSettings.add(setting);
// Sort alphabetically
filterSettings.sort(Comparator.comparing(FilterSetting::getName));
updateComboBox();
comboBox.addItem(setting);
comboBox.setSelectedItem(setting);
}
}
public boolean canRemoveFilterSetting() {
return comboBox.getSelectedItem() != customFilterSetting;
}
public void removeFilterSetting() {
if (canRemoveFilterSetting()) {
Object o = comboBox.getSelectedItem();
assert o instanceof FilterSetting;
FilterSetting f = (FilterSetting) o;
assert f != customFilterSetting;
assert filterSettings.contains(f);
NotifyDescriptor.Confirmation l = new NotifyDescriptor.Confirmation("Do you really want to remove filter profile \"" + f + "\"?", "Filter Profile");
if (getCurrentChain() != customFilterChain) {
FilterChain filter = getCurrentChain();
NotifyDescriptor.Confirmation l = new NotifyDescriptor.Confirmation("Do you really want to remove filter profile \"" + filter + "\"?", "Filter Profile");
if (DialogDisplayer.getDefault().notify(l) == NotifyDescriptor.YES_OPTION) {
filterSettings.remove(f);
updateComboBox();
comboBox.removeItem(filter);
}
}
}
private FilterSetting createFilterSetting(String name) {
FilterSetting s = new FilterSetting(name);
FilterChain chain = this.getFilterChain();
for (Filter f : chain.getFilters()) {
s.addFilter(f);
}
return s;
}
private void updateComboBoxSelection() {
List<Filter> filters = this.getFilterChain().getFilters();
boolean found = false;
for (FilterSetting s : filterSettings) {
if (s.getFilterCount() == filters.size()) {
boolean ok = true;
for (Filter f : filters) {
if (!s.containsFilter(f)) {
ok = false;
}
}
if (ok) {
if (comboBox.getSelectedItem() != s) {
comboBox.setSelectedItem(s);
}
found = true;
break;
}
}
}
if (!found && comboBox.getSelectedItem() != customFilterSetting) {
comboBox.setSelectedItem(customFilterSetting);
}
}
private class FilterChildren extends Children.Keys<Filter> implements ChangedListener<CheckNode> {
private HashMap<Filter, Node> nodeHash = new HashMap<>();
private final HashMap<Filter, Node> nodeHash = new HashMap<>();
@Override
protected Node[] createNodes(Filter filter) {
@ -262,22 +271,31 @@ public final class FilterTopComponent extends TopComponent implements LookupList
}
public FilterChildren() {
sequence.getChangedEvent().addListener(source -> addNotify());
allFiltersOrdered.getChangedEvent().addListener(source -> addNotify());
setBefore(false);
}
@Override
protected void addNotify() {
setKeys(sequence.getFilters());
setKeys(allFiltersOrdered.getFilters());
updateSelection();
}
private void updateSelection() {
Node[] nodes = getExplorerManager().getSelectedNodes();
int[] arr = new int[nodes.length];
for (int i = 0; i < nodes.length; i++) {
int index = allFiltersOrdered.getFilters().indexOf(((FilterNode) nodes[i]).getFilter());
arr[i] = index;
}
view.showSelection(arr);
}
@Override
public void changed(CheckNode source) {
FilterNode node = (FilterNode) source;
Filter f = node.getFilter();
FilterChain chain = getFilterChain();
FilterChain chain = getCurrentChain();
if (node.isSelected()) {
if (!chain.containsFilter(f)) {
chain.addFilter(f);
@ -289,14 +307,9 @@ public final class FilterTopComponent extends TopComponent implements LookupList
}
view.revalidate();
view.repaint();
updateComboBoxSelection();
}
}
public FilterChain getFilterChain() {
return filterChain;
}
private static String getJsHelperText() {
InputStream is = null;
StringBuilder sb = new StringBuilder("if (typeof importPackage === 'undefined') { try { load('nashorn:mozilla_compat.js'); } catch (e) {} }"
@ -327,80 +340,46 @@ public final class FilterTopComponent extends TopComponent implements LookupList
return sb.toString();
}
private FilterTopComponent() {
filterSettingsChangedEvent = new ChangedEvent<>(this);
initComponents();
setName(NbBundle.getMessage(FilterTopComponent.class, "CTL_FilterTopComponent"));
setToolTipText(NbBundle.getMessage(FilterTopComponent.class, "HINT_FilterTopComponent"));
// setIcon(Utilities.loadImage(ICON_PATH, true));
sequence = new FilterChain();
filterChain = new FilterChain();
ScriptEngineManager sem = new ScriptEngineManager();
engine = sem.getEngineByName("ECMAScript");
try {
engine.eval(getJsHelperText());
} catch (ScriptException ex) {
Exceptions.printStackTrace(ex);
}
engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("IO", System.out);
initFilters();
manager = new ExplorerManager();
manager.setRootContext(new AbstractNode(new FilterChildren()));
associateLookup(ExplorerUtils.createLookup(manager, getActionMap()));
view = new CheckListView();
ToolbarPool.getDefault().setPreferredIconSize(16);
Toolbar toolBar = new Toolbar();
toolBar.setBorder((Border) UIManager.get("Nb.Editor.Toolbar.border")); //NOI18N
toolBar.setMinimumSize(new Dimension(0,0)); // MacOS BUG with ToolbarWithOverflow
comboBox = new JComboBox();
toolBar.add(comboBox);
this.add(toolBar, BorderLayout.NORTH);
toolBar.add(SaveFilterSettingsAction.get(SaveFilterSettingsAction.class));
toolBar.add(RemoveFilterSettingsAction.get(RemoveFilterSettingsAction.class));
toolBar.addSeparator();
toolBar.add(NewFilterAction.get(NewFilterAction.class));
toolBar.add(RemoveFilterAction.get(RemoveFilterAction.class).createContextAwareInstance(this.getLookup()));
toolBar.add(MoveFilterUpAction.get(MoveFilterUpAction.class).createContextAwareInstance(this.getLookup()));
toolBar.add(MoveFilterDownAction.get(MoveFilterDownAction.class).createContextAwareInstance(this.getLookup()));
this.add(view, BorderLayout.CENTER);
filterSettings = new ArrayList<>();
updateComboBox();
comboBox.addActionListener(comboBoxActionListener);
setChain(filterChain);
}
public void newFilter() {
CustomFilter cf = new CustomFilter("My custom filter", "", engine);
if (cf.openInEditor()) {
sequence.addFilter(cf);
FileObject fo = getFileObject(cf);
FilterChangedListener listener = new FilterChangedListener(fo, cf);
listener.changed(cf);
cf.getChangedEvent().addListener(listener);
CustomFilter customFilter = new CustomFilter("My custom filter", "", engine);
if (customFilter.openInEditor()) {
addFilter(customFilter);
}
}
public void removeFilter(Filter f) {
com.sun.hotspot.igv.filter.CustomFilter cf = (com.sun.hotspot.igv.filter.CustomFilter) f;
public void addFilter(CustomFilter customFilter) {
allFiltersOrdered.addFilter(customFilter);
FileObject fileObject = getFileObject(customFilter);
FilterChangedListener listener = new FilterChangedListener(fileObject, customFilter);
listener.changed(customFilter);
customFilter.getChangedEvent().addListener(listener);
}
sequence.removeFilter(cf);
public void removeFilter(CustomFilter customFilter) {
allFiltersOrdered.removeFilter(customFilter);
try {
getFileObject(cf).delete();
getFileObject(customFilter).delete();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
private FileObject getFileObject(CustomFilter customFilter) {
FileObject fileObject = FileUtil.getConfigRoot().getFileObject(FOLDER_ID + "/" + customFilter.getName() + ".js");
if (fileObject == null) {
try {
fileObject = FileUtil.getConfigRoot().getFileObject(FOLDER_ID).createData(customFilter.getName() + ".js");
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
return fileObject;
}
private static class FilterChangedListener implements ChangedListener<Filter> {
private FileObject fileObject;
private CustomFilter filter;
private final CustomFilter filter;
public FilterChangedListener(FileObject fo, CustomFilter cf) {
fileObject = fo;
@ -412,10 +391,9 @@ public final class FilterTopComponent extends TopComponent implements LookupList
try {
if (!fileObject.getName().equals(filter.getName())) {
FileLock lock = fileObject.lock();
fileObject.move(lock, fileObject.getParent(), filter.getName(), "");
fileObject.move(lock, fileObject.getParent(), filter.getName(), "js");
lock.releaseLock();
FileObject newFileObject = fileObject.getParent().getFileObject(filter.getName());
fileObject = newFileObject;
fileObject = fileObject.getParent().getFileObject(filter.getName() + ".js");
}
FileLock lock = fileObject.lock();
@ -457,12 +435,11 @@ public final class FilterTopComponent extends TopComponent implements LookupList
sb.append("\n");
}
code = sb.toString();
} catch (FileNotFoundException ex) {
Exceptions.printStackTrace(ex);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} finally {
try {
assert is != null;
is.close();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
@ -472,7 +449,6 @@ public final class FilterTopComponent extends TopComponent implements LookupList
String displayName = fo.getName();
final CustomFilter cf = new CustomFilter(displayName, code, engine);
map.put(displayName, cf);
@ -480,12 +456,10 @@ public final class FilterTopComponent extends TopComponent implements LookupList
afterMap.put(cf, after);
Boolean enabled = (Boolean) fo.getAttribute(ENABLED_ID);
if (enabled != null && (boolean) enabled) {
if (enabled != null && enabled) {
enabledSet.add(cf);
}
cf.getChangedEvent().addListener(new FilterChangedListener(fo, cf));
customFilters.add(cf);
}
@ -511,9 +485,9 @@ public final class FilterTopComponent extends TopComponent implements LookupList
}
for (CustomFilter cf : customFilters) {
sequence.addFilter(cf);
addFilter(cf);
if (enabledSet.contains(cf)) {
filterChain.addFilter(cf);
defaultFilterChain.addFilter(cf);
}
}
}
@ -574,40 +548,6 @@ public final class FilterTopComponent extends TopComponent implements LookupList
return manager;
}
@Override
public void componentOpened() {
Lookup.Template<FilterChain> tpl = new Lookup.Template<>(FilterChain.class);
result = Utilities.actionsGlobalContext().lookup(tpl);
result.addLookupListener(this);
}
@Override
public void componentClosed() {
result.removeLookupListener(this);
result = null;
}
@Override
public void resultChanged(LookupEvent lookupEvent) {
setChain(Utilities.actionsGlobalContext().lookup(FilterChain.class));
}
public void setChain(FilterChain chain) {
updateComboBoxSelection();
}
private FileObject getFileObject(CustomFilter cf) {
FileObject fo = FileUtil.getConfigRoot().getFileObject(FOLDER_ID + "/" + cf.getName());
if (fo == null) {
try {
fo = FileUtil.getConfigRoot().getFileObject(FOLDER_ID).createData(cf.getName());
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
return fo;
}
@Override
public boolean requestFocus(boolean temporary) {
view.requestFocus();
@ -626,44 +566,73 @@ public final class FilterTopComponent extends TopComponent implements LookupList
view.requestFocus();
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeInt(filterSettings.size());
for (FilterSetting f : filterSettings) {
out.writeUTF(f.getName());
out.writeInt(f.getFilterCount());
for (Filter filter : f.getFilters()) {
out.writeUTF(getCurrentChain().getName());
out.writeInt(comboBox.getItemCount());
for (int i=0; i<comboBox.getItemCount(); i++) {
FilterChain filterChain = comboBox.getItemAt(i);
out.writeUTF(filterChain.getName());
out.writeInt(filterChain.getFilters().size());
for (Filter filter : filterChain.getFilters()) {
CustomFilter cf = (CustomFilter) filter;
out.writeUTF(cf.getName());
}
}
CustomFilter prev = null;
for (Filter f : this.sequence.getFilters()) {
CustomFilter cf = (CustomFilter) f;
FileObject fo = getFileObject(cf);
if (getFilterChain().containsFilter(cf)) {
fo.setAttribute(ENABLED_ID, true);
} else {
fo.setAttribute(ENABLED_ID, false);
}
if (prev == null) {
fo.setAttribute(AFTER_ID, null);
} else {
fo.setAttribute(AFTER_ID, prev.getName());
}
prev = cf;
out.writeInt(allFiltersOrdered.getFilters().size());
for (Filter filter : allFiltersOrdered.getFilters()) {
out.writeUTF(filter.getName());
}
}
public CustomFilter findFilter(String name) {
for (Filter f : sequence.getFilters()) {
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
String selectedChainName = in.readUTF();
int filterSettingsCount = in.readInt();
for (int i = 0; i < filterSettingsCount; i++) {
String name = in.readUTF();
int filterCount = in.readInt();
FilterChain filterChain = new FilterChain(name);
for (int j = 0; j < filterCount; j++) {
String filterName = in.readUTF();
CustomFilter filter = findFilter(filterName);
if (filter != null) {
filterChain.addFilter(filter);
}
}
if (Objects.equals(filterChain.getName(), customFilterChain.getName())) {
setCustomFilterChain(filterChain);
} else {
for (int cnt=0; cnt<comboBox.getItemCount(); cnt++) {
FilterChain s = comboBox.getItemAt(cnt);
if (s.getName().equals(name)) {
comboBox.removeItem(s);
}
}
comboBox.addItem(filterChain);
}
if (selectedChainName.equals(filterChain.getName())) {
selectFilterChain(filterChain);
}
}
ArrayList<String> order = new ArrayList<>();
int filterOrderCount = in.readInt();
for (int i = 0; i < filterOrderCount; i++) {
String name = in.readUTF();
order.add(name);
}
allFiltersOrdered.sortBy(order);
}
public CustomFilter findFilter(String name) {
for (Filter f : allFiltersOrdered.getFilters()) {
CustomFilter cf = (CustomFilter) f;
if (cf.getName().equals(name)) {
return cf;
@ -672,26 +641,4 @@ public final class FilterTopComponent extends TopComponent implements LookupList
return null;
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
int filterSettingsCount = in.readInt();
for (int i = 0; i < filterSettingsCount; i++) {
String name = in.readUTF();
FilterSetting s = new FilterSetting(name);
int filterCount = in.readInt();
for (int j = 0; j < filterCount; j++) {
String filterName = in.readUTF();
CustomFilter filter = findFilter(filterName);
if (filter != null) {
s.addFilter(filter);
}
}
filterSettings.add(s);
}
updateComboBox();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@ -41,7 +41,7 @@ public final class MoveFilterDownAction extends CookieAction {
protected void performAction(Node[] activatedNodes) {
for (Node n : activatedNodes) {
Filter c = n.getLookup().lookup(Filter.class);
FilterTopComponent.findInstance().getSequence().moveFilterDown(c);
FilterTopComponent.findInstance().getAllFiltersOrdered().moveFilterDown(c);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@ -41,7 +41,7 @@ public final class MoveFilterUpAction extends CookieAction {
protected void performAction(Node[] activatedNodes) {
for (Node n : activatedNodes) {
Filter c = n.getLookup().lookup(Filter.class);
FilterTopComponent.findInstance().getSequence().moveFilterUp(c);
FilterTopComponent.findInstance().getAllFiltersOrdered().moveFilterUp(c);
}
}

View File

@ -23,6 +23,7 @@
*/
package com.sun.hotspot.igv.filterwindow.actions;
import com.sun.hotspot.igv.filter.CustomFilter;
import com.sun.hotspot.igv.filter.Filter;
import com.sun.hotspot.igv.filterwindow.FilterTopComponent;
import javax.swing.Action;
@ -54,8 +55,8 @@ public final class RemoveFilterAction extends CookieAction {
options[2]);
if (n == JOptionPane.YES_OPTION) {
for (int i = 0; i < activatedNodes.length; i++) {
FilterTopComponent.findInstance().removeFilter(activatedNodes[i].getLookup().lookup(Filter.class));
for (Node activatedNode : activatedNodes) {
FilterTopComponent.findInstance().removeFilter(activatedNode.getLookup().lookup(CustomFilter.class));
}
}
}

View File

@ -2,74 +2,74 @@
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
<folder name="Filters">
<file name="Color by category" url="filters/color.filter">
<file name="Color by category.js" url="filters/color.filter">
<attr name="enabled" boolvalue="true"/>
</file>
<file name="Color by execution frequency" url="filters/colorFrequency.filter">
<file name="Color by execution frequency.js" url="filters/colorFrequency.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Color by category"/>
</file>
<file name="Show node warnings" url="filters/showWarnings.filter">
<file name="Show node warnings.js" url="filters/showWarnings.filter">
<attr name="enabled" boolvalue="true"/>
<attr name="after" stringvalue="Color by execution frequency"/>
</file>
<file name="Simplify graph" url="filters/structural.filter">
<file name="Simplify graph.js" url="filters/structural.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Show node warnings"/>
</file>
<file name="Hide data subgraph" url="filters/hideData.filter">
<file name="Hide data subgraph.js" url="filters/hideData.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Simplify graph"/>
</file>
<file name="Hide memory subgraph" url="filters/hideMemory.filter">
<file name="Hide memory subgraph.js" url="filters/hideMemory.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide data subgraph"/>
</file>
<file name="Hide control subgraph" url="filters/hideControl.filter">
<file name="Hide control subgraph.js" url="filters/hideControl.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide memory subgraph"/>
</file>
<file name="Hide mixed subgraph" url="filters/hideMixed.filter">
<file name="Hide mixed subgraph.js" url="filters/hideMixed.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide control subgraph"/>
</file>
<file name="Hide other subgraph" url="filters/hideOther.filter">
<file name="Hide other subgraph.js" url="filters/hideOther.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide mixed subgraph"/>
</file>
<file name="Show control flow only" url="filters/onlyControlFlow.filter">
<file name="Show control flow only.js" url="filters/onlyControlFlow.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide other subgraph"/>
</file>
<file name="Hide data edges" url="filters/hideDataEdges.filter">
<file name="Hide data edges.js" url="filters/hideDataEdges.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Show control flow only"/>
</file>
<file name="Hide memory edges" url="filters/hideMemoryEdges.filter">
<file name="Hide memory edges.js" url="filters/hideMemoryEdges.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide data edges"/>
</file>
<file name="Hide control edges" url="filters/hideControlEdges.filter">
<file name="Hide control edges.js" url="filters/hideControlEdges.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide memory edges"/>
</file>
<file name="Hide mixed edges" url="filters/hideMixedEdges.filter">
<file name="Hide mixed edges.js" url="filters/hideMixedEdges.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide control edges"/>
</file>
<file name="Hide other edges" url="filters/hideOtherEdges.filter">
<file name="Hide other edges.js" url="filters/hideOtherEdges.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide mixed edges"/>
</file>
<file name="Hide root block" url="filters/hideRootBlock.filter">
<file name="Hide root block.js" url="filters/hideRootBlock.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide other edges"/>
</file>
<file name="Hide uncommon trap blocks" url="filters/hideUncommonTrapBlocks.filter">
<file name="Hide uncommon trap blocks.js" url="filters/hideUncommonTrapBlocks.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide root block"/>
</file>
<file name="Hide exception blocks" url="filters/hideExceptionBlocks.filter">
<file name="Hide exception blocks.js" url="filters/hideExceptionBlocks.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide uncommon trap blocks"/>
</file>

View File

@ -45,7 +45,18 @@ public class RangeSliderModel implements ChangedEventProvider<RangeSliderModel>
private int secondPosition;
private List<Color> colors;
public RangeSliderModel(RangeSliderModel model) {
firstPosition = model.getFirstPosition();
secondPosition = model.getSecondPosition();
changedEvent = new ChangedEvent<>(this);
colorChangedEvent = new ChangedEvent<>(this);
positions = new ArrayList<>(model.getPositions());
colors = new ArrayList<>(model.getColors());
}
public RangeSliderModel() {
firstPosition = -1;
secondPosition = -1;
changedEvent = new ChangedEvent<>(this);
colorChangedEvent = new ChangedEvent<>(this);
positions = new ArrayList<>();

View File

@ -487,7 +487,6 @@ public class DiagramScene extends ObjectScene implements DiagramViewer, DoubleCl
}
}
});
update();
}
@Override
@ -638,7 +637,6 @@ public class DiagramScene extends ObjectScene implements DiagramViewer, DoubleCl
}
private void graphChanged() {
update();
centerRootNode();
addUndo();
}

View File

@ -52,13 +52,15 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
private ArrayList<InputGraph> graphs;
private Set<Integer> hiddenNodes;
private Set<Integer> selectedNodes;
private final FilterChain filterChain;
private FilterChain filterChain;
private final FilterChain customFilterChain;
private final FilterChain filtersOrder;
private Diagram diagram;
private InputGraph cachedInputGraph;
private final ChangedEvent<DiagramViewModel> diagramChangedEvent;
private final ChangedEvent<DiagramViewModel> graphChangedEvent;
private final ChangedEvent<DiagramViewModel> selectedNodesChangedEvent;
private final ChangedEvent<DiagramViewModel> hiddenNodesChangedEvent;
private final ChangedEvent<DiagramViewModel> diagramChangedEvent = new ChangedEvent<>(this);
private final ChangedEvent<DiagramViewModel> graphChangedEvent = new ChangedEvent<>(this);
private final ChangedEvent<DiagramViewModel> selectedNodesChangedEvent = new ChangedEvent<>(this);
private final ChangedEvent<DiagramViewModel> hiddenNodesChangedEvent = new ChangedEvent<>(this);
private ChangedListener<InputGraph> titleChangedListener = g -> {};
private boolean showSea;
private boolean showBlocks;
@ -68,7 +70,10 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
private boolean hideDuplicates;
private static boolean globalSelection = false;
private final ChangedListener<FilterChain> filterChainChangedListener = source -> filterChanged();
private final ChangedListener<FilterChain> filterChainChangedListener = changedFilterChain -> {
assert filterChain == changedFilterChain;
rebuildDiagram();
};
public Group getGroup() {
return group;
@ -78,36 +83,44 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
return globalSelection;
}
public void setGlobalSelection(boolean enable) {
public void setGlobalSelection(boolean enable, boolean fire) {
globalSelection = enable;
diagramChangedEvent.fire();
if (fire && enable) {
diagramChangedEvent.fire();
}
}
public boolean getShowSea() {
return showSea;
}
public void setShowSea(boolean b) {
showSea = b;
diagramChangedEvent.fire();
public void setShowSea(boolean enable) {
showSea = enable;
if (enable) {
diagramChangedEvent.fire();
}
}
public boolean getShowBlocks() {
return showBlocks;
}
public void setShowBlocks(boolean b) {
showBlocks = b;
diagramChangedEvent.fire();
public void setShowBlocks(boolean enable) {
showBlocks = enable;
if (enable) {
diagramChangedEvent.fire();
}
}
public boolean getShowCFG() {
return showCFG;
}
public void setShowCFG(boolean b) {
showCFG = b;
diagramChangedEvent.fire();
public void setShowCFG(boolean enable) {
showCFG = enable;
if (enable) {
diagramChangedEvent.fire();
}
}
public boolean getShowNodeHull() {
@ -147,33 +160,8 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
return hideDuplicates;
}
public DiagramViewModel(InputGraph graph) {
FilterChainProvider provider = Lookup.getDefault().lookup(FilterChainProvider.class);
if (provider == null) {
filterChain = new FilterChain();
} else {
filterChain = provider.getFilterChain();
}
globalSelection = GlobalSelectionAction.get(GlobalSelectionAction.class).isSelected();
showSea = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.SEA_OF_NODES;
showBlocks = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CLUSTERED_SEA_OF_NODES;
showCFG = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CONTROL_FLOW_GRAPH;
showNodeHull = true;
showEmptyBlocks = true;
group = graph.getGroup();
hiddenNodes = new HashSet<>();
selectedNodes = new HashSet<>();
diagramChangedEvent = new ChangedEvent<>(this);
graphChangedEvent = new ChangedEvent<>(this);
selectedNodesChangedEvent = new ChangedEvent<>(this);
hiddenNodesChangedEvent = new ChangedEvent<>(this);
super.getChangedEvent().addListener(this);
// If the group has been emptied, all corresponding graph views
// will be closed, so do nothing.
ChangedListener<Group> groupContentChangedListener = g -> {
private void initGroup() {
group.getChangedEvent().addListener(g -> {
assert g == group;
if (group.getGraphs().isEmpty()) {
// If the group has been emptied, all corresponding graph views
@ -182,12 +170,60 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
}
filterGraphs();
setSelectedNodes(selectedNodes);
};
group.getChangedEvent().addListener(groupContentChangedListener);
filterChain.getChangedEvent().addListener(filterChainChangedListener);
});
filterGraphs();
super.getChangedEvent().addListener(this);
}
public DiagramViewModel(DiagramViewModel model) {
super(model);
globalSelection = false;
group = model.getGroup();
initGroup();
graphs = new ArrayList<>(model.graphs);
// initialize the filters from a model
FilterChainProvider provider = Lookup.getDefault().lookup(FilterChainProvider.class);
assert provider != null;
customFilterChain = provider.createNewCustomFilterChain();
customFilterChain.clearFilters();
customFilterChain.addFilters(model.getCustomFilterChain().getFilters());
setFilterChain(model.getFilterChain());
filtersOrder = provider.getAllFiltersOrdered();
globalSelection = GlobalSelectionAction.get(GlobalSelectionAction.class).isSelected();
showCFG = model.getShowCFG();
showSea = model.getShowSea();
showBlocks = model.getShowBlocks();
showNodeHull = model.getShowNodeHull();
showEmptyBlocks = model.getShowEmptyBlocks();
hideDuplicates = model.getHideDuplicates();
hiddenNodes = new HashSet<>(model.getHiddenNodes());
selectedNodes = new HashSet<>();
changed(this);
}
public DiagramViewModel(InputGraph graph) {
group = graph.getGroup();
initGroup();
FilterChainProvider provider = Lookup.getDefault().lookup(FilterChainProvider.class);
assert provider != null;
customFilterChain = provider.createNewCustomFilterChain();
setFilterChain(provider.getFilterChain());
filtersOrder = provider.getAllFiltersOrdered();
globalSelection = GlobalSelectionAction.get(GlobalSelectionAction.class).isSelected();
showSea = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.SEA_OF_NODES;
showBlocks = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CLUSTERED_SEA_OF_NODES;
showCFG = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CONTROL_FLOW_GRAPH;
showNodeHull = true;
showEmptyBlocks = true;
hideDuplicates = false;
hiddenNodes = new HashSet<>();
selectedNodes = new HashSet<>();
selectGraph(graph);
}
@ -290,13 +326,37 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
hiddenNodesChangedEvent.fire();
}
public FilterChain getSequenceFilterChain() {
return filterChain;
private void setFilterChain(FilterChain newFC) {
assert newFC != null && customFilterChain != null;
if (filterChain != null) {
filterChain.getChangedEvent().removeListener(filterChainChangedListener);
}
if (newFC.getName().equals(customFilterChain.getName())) {
filterChain = customFilterChain;
} else {
filterChain = newFC;
}
filterChain.getChangedEvent().addListener(filterChainChangedListener);
}
private void filterChanged() {
rebuildDiagram();
diagramChangedEvent.fire();
void activateModel() {
FilterChainProvider provider = Lookup.getDefault().lookup(FilterChainProvider.class);
if (provider != null) {
provider.setCustomFilterChain(customFilterChain);
provider.selectFilterChain(filterChain);
// link the Filters window with this model
provider.setFilterChainSelectionChangedListener(l -> {
// this function is called when user selects a different filter profile for this model
setFilterChain(provider.getFilterChain());
rebuildDiagram();
});
}
}
void close() {
filterChain.getChangedEvent().removeListener(filterChainChangedListener);
getChangedEvent().fire();
}
private void rebuildDiagram() {
@ -312,7 +372,8 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
Settings.get().get(Settings.NODE_TEXT, Settings.NODE_TEXT_DEFAULT),
Settings.get().get(Settings.NODE_SHORT_TEXT, Settings.NODE_SHORT_TEXT_DEFAULT),
Settings.get().get(Settings.NODE_TINY_TEXT, Settings.NODE_TINY_TEXT_DEFAULT));
getFilterChain().apply(diagram, getSequenceFilterChain());
diagram.setCFG(getShowCFG());
filterChain.applyInOrder(diagram, filtersOrder);
if (graph.isDiffGraph()) {
ColorFilter f = new ColorFilter("");
f.addRule(stateColorRule("same", Color.white));
@ -321,12 +382,17 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
f.addRule(stateColorRule("deleted", Color.red));
f.apply(diagram);
}
diagramChangedEvent.fire();
}
public FilterChain getFilterChain() {
return filterChain;
}
public FilterChain getCustomFilterChain() {
return customFilterChain;
}
/*
* Select the set of graphs to be presented.
*/
@ -403,7 +469,6 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
}
public Diagram getDiagram() {
diagram.setCFG(getShowCFG());
return diagram;
}
@ -431,11 +496,6 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
titleChangedListener = titleCallback::accept;
}
void close() {
filterChain.getChangedEvent().removeListener(filterChainChangedListener);
getChangedEvent().fire();
}
Iterable<InputGraph> getGraphsForward() {
return () -> new Iterator<InputGraph>() {
int index = getFirstPosition();

View File

@ -28,11 +28,10 @@ import com.sun.hotspot.igv.data.Group;
import com.sun.hotspot.igv.data.InputGraph;
import com.sun.hotspot.igv.data.InputNode;
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.settings.Settings;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.util.LookupHistory;
import com.sun.hotspot.igv.util.RangeSlider;
import com.sun.hotspot.igv.util.StringUtils;
import com.sun.hotspot.igv.view.actions.*;
import java.awt.*;
import java.awt.event.MouseEvent;
@ -46,7 +45,6 @@ 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;
@ -70,15 +68,12 @@ public final class EditorTopComponent extends TopComponent implements TopCompone
private final JPanel centerPanel;
private final CardLayout cardLayout;
private final Toolbar quickSearchToolbar;
private boolean useBoldDisplayName = false;
private static final JPanel quickSearchPresenter = (JPanel) ((Presenter.Toolbar) Utilities.actionsForPath("Actions/Search").get(0)).getToolbarPresenter();
private static final String PREFERRED_ID = "EditorTopComponent";
private static final String SATELLITE_STRING = "satellite";
private static final String SCENE_STRING = "scene";
public EditorTopComponent(InputGraph graph) {
this(new DiagramViewModel(graph));
}
public EditorTopComponent(DiagramViewModel diagramViewModel) {
initComponents();
@ -372,9 +367,35 @@ public final class EditorTopComponent extends TopComponent implements TopCompone
scene.getComponent().requestFocus();
}
@Override
public void setDisplayName(String displayName) {
super.setDisplayName(displayName);
if (useBoldDisplayName) {
setHtmlDisplayName("<html><b>" + StringUtils.escapeHTML(getDisplayName()) + "</b>");
} else {
setHtmlDisplayName(getDisplayName());
}
}
private void setBoldDisplayName(boolean bold) {
useBoldDisplayName = bold;
setDisplayName(getDisplayName());
}
@Override
protected void componentActivated() {
super.componentActivated();
getModel().activateModel();
WindowManager manager = WindowManager.getDefault();
for (Mode m : manager.getModes()) {
for (TopComponent topComponent : manager.getOpenedTopComponents(m)) {
if (topComponent instanceof EditorTopComponent) {
EditorTopComponent editor = (EditorTopComponent) topComponent;
editor.setBoldDisplayName(false);
}
}
}
setBoldDisplayName(true);
quickSearchToolbar.add(quickSearchPresenter);
quickSearchPresenter.revalidate();
}
@ -390,19 +411,23 @@ public final class EditorTopComponent extends TopComponent implements TopCompone
@Override
public TopComponent cloneComponent() {
DiagramViewModel model = new DiagramViewModel(getModel().getFirstGraph());
if (getModel().getGraph().isDiffGraph()) {
model.setPositions(getModel().getFirstPosition(), getModel().getSecondPosition());
}
model.setHiddenNodes(new HashSet<>(getModel().getHiddenNodes()));
model.setShowCFG(getModel().getShowCFG());
model.setShowSea(getModel().getShowSea());
model.setShowBlocks(getModel().getShowBlocks());
model.setShowNodeHull(getModel().getShowNodeHull());
model.setShowEmptyBlocks(getModel().getShowEmptyBlocks());
model.setHideDuplicates(getModel().getHideDuplicates());
DiagramViewModel model = new DiagramViewModel(getModel());
model.setGlobalSelection(false, false);
EditorTopComponent etc = new EditorTopComponent(model);
Set<InputNode> selectedNodes = new HashSet<>();
for (Figure figure : getModel().getSelectedFigures()) {
selectedNodes.add(figure.getInputNode());
}
etc.addSelectedNodes(selectedNodes, false);
model.setGlobalSelection(GlobalSelectionAction.get(GlobalSelectionAction.class).isSelected(), false);
etc.resetUndoRedo();
int currentZoomLevel = scene.getZoomPercentage();
SwingUtilities.invokeLater(() -> {
etc.setZoomLevel(currentZoomLevel);
etc.centerSelectedNodes();
});
return etc;
}

View File

@ -62,9 +62,9 @@ public class GraphViewerImplementation implements GraphViewer {
return;
}
}
EditorTopComponent tc = new EditorTopComponent(graph);
tc.open();
tc.requestActive();
DiagramViewModel model = new DiagramViewModel(graph);
EditorTopComponent etc = new EditorTopComponent(model);
etc.open();
etc.requestActive();
}
}

View File

@ -74,7 +74,7 @@ public final class GlobalSelectionAction extends CallableSystemAction {
putValue(SELECTED_KEY, isSelected);
EditorTopComponent editor = EditorTopComponent.getActive();
if (editor != null) {
SwingUtilities.invokeLater(() -> editor.getModel().setGlobalSelection(isSelected));
SwingUtilities.invokeLater(() -> editor.getModel().setGlobalSelection(isSelected, true));
}
}