Skip to content

Commit 5feaf25

Browse files
aptmacjessyec-s
andcommitted
6364: Improvements to the Thread Graph
Co-authored-by: Jessye Coleman-Shapiro <jescolem@openjdk.org> Reviewed-by: ghb
1 parent c3f4920 commit 5feaf25

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+5221
-360
lines changed

application/org.openjdk.jmc.flightrecorder.ui/defaultPages.xml

Lines changed: 290 additions & 154 deletions
Large diffs are not rendered by default.

application/org.openjdk.jmc.flightrecorder.ui/plugin.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@
218218
class="org.openjdk.jmc.flightrecorder.ui.pages.ThreadsPage$ThreadsPageFactory"
219219
id="org.openjdk.jmc.flightrecorder.ui.threads">
220220
</factory>
221+
<factory
222+
class="org.openjdk.jmc.flightrecorder.ui.pages.ThreadsPageLegacy$ThreadsPageLegacyFactory"
223+
id="org.openjdk.jmc.flightrecorder.ui.threadslegacy">
224+
</factory>
221225
<factory
222226
class="org.openjdk.jmc.flightrecorder.ui.pages.HeapPage$HeapPageFactory"
223227
id="org.openjdk.jmc.flightrecorder.ui.heap">

application/org.openjdk.jmc.flightrecorder.ui/src/main/java/org/openjdk/jmc/flightrecorder/ui/common/DataPageToolkit.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
*
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -155,6 +155,7 @@
155155
import org.openjdk.jmc.ui.handlers.ActionToolkit;
156156
import org.openjdk.jmc.ui.handlers.MCContextMenuManager;
157157
import org.openjdk.jmc.ui.misc.ChartCanvas;
158+
import org.openjdk.jmc.ui.misc.ChartTextCanvas;
158159
import org.openjdk.jmc.ui.misc.CompositeToolkit;
159160
import org.openjdk.jmc.ui.misc.DisplayToolkit;
160161
import org.openjdk.jmc.ui.misc.FilterEditor;
@@ -312,6 +313,10 @@ public static void setChart(ChartCanvas canvas, XYChart chart, Consumer<IItemCol
312313
setChart(canvas, chart, selectionListener, null);
313314
}
314315

316+
public static void setChart(ChartTextCanvas canvas, XYChart chart, Consumer<IItemCollection> selectionListener) {
317+
setChart(canvas, chart, selectionListener, null);
318+
}
319+
315320
public static void setChart(
316321
ChartCanvas canvas, XYChart chart, Consumer<IItemCollection> selectionListener,
317322
Consumer<IRange<IQuantity>> selectRangeConsumer) {
@@ -343,6 +348,37 @@ public void run() {
343348
canvas.setChart(chart);
344349
}
345350

351+
public static void setChart(
352+
ChartTextCanvas canvas, XYChart chart, Consumer<IItemCollection> selectionListener,
353+
Consumer<IRange<IQuantity>> selectRangeConsumer) {
354+
IMenuManager contextMenu = canvas.getContextMenu();
355+
contextMenu.removeAll();
356+
canvas.getContextMenu().add(new Action(Messages.CHART_ZOOM_TO_SELECTED_RANGE) {
357+
@Override
358+
public void run() {
359+
IQuantity selectionStart = chart.getSelectionStart();
360+
IQuantity selectionEnd = chart.getSelectionEnd();
361+
if (selectionStart == null || selectionEnd == null) {
362+
chart.clearVisibleRange();
363+
} else {
364+
chart.setVisibleRange(selectionStart, selectionEnd);
365+
}
366+
canvas.redrawChartText();
367+
}
368+
});
369+
370+
canvas.setSelectionListener(() -> {
371+
selectionListener.accept(ItemRow.getRangeSelection(chart, JfrAttributes.LIFETIME));
372+
IQuantity start = chart.getSelectionStart();
373+
IQuantity end = chart.getSelectionEnd();
374+
if (selectRangeConsumer != null) {
375+
selectRangeConsumer
376+
.accept(start != null && end != null ? QuantityRange.createWithEnd(start, end) : null);
377+
}
378+
});
379+
canvas.setChart(chart);
380+
}
381+
346382
public static void setChart(
347383
ChartCanvas canvas, XYChart chart, IAttribute<IQuantity> selectionAttribute,
348384
Consumer<IItemCollection> selectionListener) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2020, Red Hat Inc. All rights reserved.
4+
*
5+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6+
*
7+
* The contents of this file are subject to the terms of either the Universal Permissive License
8+
* v 1.0 as shown at http://oss.oracle.com/licenses/upl
9+
*
10+
* or the following license:
11+
*
12+
* Redistribution and use in source and binary forms, with or without modification, are permitted
13+
* provided that the following conditions are met:
14+
*
15+
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
16+
* and the following disclaimer.
17+
*
18+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
19+
* conditions and the following disclaimer in the documentation and/or other materials provided with
20+
* the distribution.
21+
*
22+
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
23+
* endorse or promote products derived from this software without specific prior written permission.
24+
*
25+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
26+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
27+
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
28+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
32+
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33+
*/
34+
package org.openjdk.jmc.flightrecorder.ui.common;
35+
36+
import org.eclipse.swt.SWT;
37+
import org.eclipse.swt.events.ShellAdapter;
38+
import org.eclipse.swt.events.ShellEvent;
39+
import org.eclipse.swt.graphics.Point;
40+
import org.eclipse.swt.graphics.Rectangle;
41+
import org.eclipse.swt.layout.GridData;
42+
import org.eclipse.swt.layout.GridLayout;
43+
import org.eclipse.swt.widgets.Button;
44+
import org.eclipse.swt.widgets.Composite;
45+
import org.eclipse.swt.widgets.Display;
46+
import org.eclipse.swt.widgets.Event;
47+
import org.eclipse.swt.widgets.Listener;
48+
import org.eclipse.swt.widgets.Shell;
49+
50+
import org.openjdk.jmc.flightrecorder.ui.common.LaneEditor.EditLanesContainer;
51+
import org.openjdk.jmc.flightrecorder.ui.messages.internal.Messages;
52+
import org.openjdk.jmc.ui.common.util.Environment;
53+
import org.openjdk.jmc.ui.common.util.Environment.OSType;
54+
import org.openjdk.jmc.ui.handlers.MCContextMenuManager;
55+
56+
public class DropdownLaneFilter extends Composite {
57+
private static final int EXTRA_SHELL_WIDTH = 300;
58+
private static final int SHELL_HEIGHT = 500;
59+
private Button dropdownButton;
60+
private GridLayout layout;
61+
private MCContextMenuManager[] mms;
62+
private Shell shell;
63+
private ThreadGraphLanes lanes;
64+
private EditLanesContainer container;
65+
66+
public DropdownLaneFilter(Composite parent, ThreadGraphLanes lanes, MCContextMenuManager[] mms) {
67+
super(parent, SWT.NONE);
68+
this.lanes = lanes;
69+
this.mms = mms;
70+
this.layout = new GridLayout();
71+
layout.marginHeight = 0;
72+
layout.marginWidth = 0;
73+
setLayout(layout);
74+
dropdownButton = new Button(this, SWT.TOGGLE);
75+
dropdownButton.setLayoutData(new GridData(GridData.FILL_BOTH));
76+
dropdownButton.setText(Messages.DropdownLaneFilter_THREAD_STATE_SELECTION);
77+
dropdownButton.addListener(SWT.MouseUp, new Listener() {
78+
@Override
79+
public void handleEvent(Event e) {
80+
/*
81+
* Windows: works IF the menu item that is toggled is also highlight. e.g, if the
82+
* user wanted to toggle the Java Compiler lanes, then it's not enough to just click
83+
* the checkbox - the Java Compiler menu item must be highlighted at the time of
84+
* toggling
85+
*
86+
* MacOS: There are currently issues with paint timings with Mac OS at the moment
87+
* where toggling an activity lane from the dropdown does not redraw the chart. This
88+
* may be related to the Windows issue, and may be a SWT limitation.
89+
*/
90+
if (Environment.getOSType() != OSType.LINUX) {
91+
lanes.openEditLanesDialog(mms, false);
92+
dropdownButton.setSelection(false);
93+
} else {
94+
if (dropdownButton.getSelection()) {
95+
displayDropdown();
96+
}
97+
}
98+
}
99+
});
100+
}
101+
102+
/**
103+
* Creates a new shell which is positioned below the dropdown button. This new shell creates the
104+
* appearance of a dropdown component, and it's contents will be the TypeFilterBuilder as found
105+
* in the Edit Thread Lanes dialog.
106+
*/
107+
private void displayDropdown() {
108+
Point p = dropdownButton.getParent().toDisplay(dropdownButton.getLocation());
109+
Point size = dropdownButton.getSize();
110+
Rectangle shellRect = new Rectangle(p.x, p.y + size.y, size.x, 0);
111+
112+
shell = new Shell(DropdownLaneFilter.this.getShell(), SWT.BORDER);
113+
shell.addShellListener(new ShellAdapter() {
114+
115+
public void shellDeactivated(ShellEvent e) {
116+
if (!isCursorOnTopOfButton()) {
117+
// If the shell is closed without clicking the button (i.e., not forcing
118+
// a toggle), then the button must be toggled programmatically.
119+
dropdownButton.setSelection(false);
120+
}
121+
disposeDropdown();
122+
}
123+
});
124+
125+
shell.setLayout(this.layout);
126+
shell.setSize(shellRect.width + EXTRA_SHELL_WIDTH, SHELL_HEIGHT);
127+
shell.setLocation(shellRect.x, shellRect.y);
128+
129+
container = new EditLanesContainer(shell, lanes.getTypeTree(), lanes.getLaneDefinitions(), () -> updateChart());
130+
container.setLayoutData(new GridData(GridData.FILL_BOTH));
131+
shell.open();
132+
}
133+
134+
private void disposeDropdown() {
135+
if (shell != null && !shell.isDisposed()) {
136+
shell.close();
137+
}
138+
}
139+
140+
/**
141+
* Determine whether or not the mouse cursor is overlapping the dropdown button. An open
142+
* dropdown shell should close when the user clicks the button. In Linux, the MouseListener on
143+
* the button will fire. In Windows, the shell has priority and the MouseListener doesn't get
144+
* activated. This function is to be used in the ShellAdapter to determine if the user closed
145+
* the shell by trying to click the button, or by clicking away from the dropdown shell.
146+
*
147+
* @return true if the mouse cursor is on top of the button
148+
*/
149+
private boolean isCursorOnTopOfButton() {
150+
Point cursor = Display.getCurrent().getCursorLocation();
151+
Point buttonLoc = dropdownButton.toDisplay(1, 1);
152+
Rectangle buttonRect = new Rectangle(buttonLoc.x, buttonLoc.y, dropdownButton.getSize().x,
153+
dropdownButton.getSize().y);
154+
return buttonRect.contains(cursor);
155+
}
156+
157+
private void updateChart() {
158+
lanes.buildChart();
159+
lanes.updateContextMenus(mms, false);
160+
}
161+
}

application/org.openjdk.jmc.flightrecorder.ui/src/main/java/org/openjdk/jmc/flightrecorder/ui/common/FlavorSelector.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
*
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -65,7 +65,9 @@
6565
import org.eclipse.swt.widgets.Canvas;
6666
import org.eclipse.swt.widgets.Composite;
6767
import org.eclipse.swt.widgets.Control;
68+
import org.eclipse.swt.widgets.Event;
6869
import org.eclipse.swt.widgets.Label;
70+
import org.eclipse.swt.widgets.Listener;
6971
import org.eclipse.ui.forms.widgets.Form;
7072

7173
import org.openjdk.jmc.common.IDisplayable;
@@ -301,7 +303,6 @@ private FlavorSelector(Form form, IItemFilter filter, List<IAttribute<?>> attrib
301303
sameThreadsButton.addSelectionListener(new SameThreadsSelectionListener());
302304

303305
// FIXME: Persist state for above checkboxes?
304-
305306
onShow.ifPresent(on -> {
306307
Label rangeLabel = new Label(selectorRow, SWT.NONE);
307308
rangeLabel.setLayoutData(GridDataFactory.swtDefaults().create());
@@ -367,10 +368,9 @@ private static String formatRange(IRange<IQuantity> range) {
367368
}
368369

369370
public void enableSelection() {
370-
boolean enabled = true;
371-
pageContainer.getSelectionStore().setCurrentActive(enabled);
372-
selectionCombo.getCombo().setEnabled(enabled);
373-
flavorCombo.getCombo().setEnabled(enabled);
371+
pageContainer.getSelectionStore().setCurrentActive(true);
372+
selectionCombo.getCombo().setEnabled(true);
373+
flavorCombo.getCombo().setEnabled(true);
374374
// FIXME: Make sure not to call useFlavor twice during initialization.
375375
// IItemStreamFlavor flavor = null;
376376
// if (enabled) {
@@ -384,15 +384,14 @@ public FlavorSelectorState getFlavorSelectorState() {
384384
}
385385

386386
private IItemStreamFlavor getSelectedFlavor() {
387-
IItemStreamFlavor flavor = null;
388387
ISelection s = flavorCombo.getSelection();
389388
if (s instanceof IStructuredSelection) {
390389
Object obj = ((IStructuredSelection) s).getFirstElement();
391390
if (obj instanceof IItemStreamFlavor) {
392-
flavor = (IItemStreamFlavor) obj;
391+
return (IItemStreamFlavor) obj;
393392
}
394393
}
395-
return flavor;
394+
return null;
396395
}
397396

398397
private static final class SelectionComboContentProvider implements IStructuredContentProvider {

0 commit comments

Comments
 (0)