| /******************************************************************************* |
| * Copyright (c) 2016, 2019 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Patrick Tasse - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.jface.viewers.ITableLabelProvider; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swtbot.swt.finder.SWTBot; |
| import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; |
| import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; |
| import org.eclipse.swtbot.swt.finder.results.ArrayResult; |
| import org.eclipse.swtbot.swt.finder.results.ListResult; |
| import org.eclipse.swtbot.swt.finder.results.Result; |
| import org.eclipse.swtbot.swt.finder.results.VoidResult; |
| import org.eclipse.swtbot.swt.finder.waits.Conditions; |
| import org.eclipse.swtbot.swt.finder.waits.WaitForObjectCondition; |
| import org.eclipse.swtbot.swt.finder.widgets.AbstractSWTBotControl; |
| import org.eclipse.swtbot.swt.finder.widgets.SWTBotRootMenu; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.ITimeDataProvider; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl; |
| |
| /** |
| * SWTBot class representing a time graph entry |
| */ |
| public class SWTBotTimeGraphEntry extends AbstractSWTBotControl<TimeGraphControl> { |
| |
| private final ITimeGraphEntry fEntry; |
| |
| /** |
| * Constructor |
| * |
| * @param w |
| * the widget |
| * @param entry |
| * the time graph entry |
| * |
| * @throws WidgetNotFoundException |
| * if the widget is <code>null</code> or widget has been |
| * disposed. |
| */ |
| public SWTBotTimeGraphEntry(TimeGraphControl w, ITimeGraphEntry entry) throws WidgetNotFoundException { |
| super(w); |
| fEntry = entry; |
| } |
| |
| @Override |
| protected SWTBotRootMenu contextMenu(final Control control) throws WidgetNotFoundException { |
| Rectangle bounds = absoluteLocation(); |
| if (bounds == null) { |
| return null; |
| } |
| UIThreadRunnable.syncExec(new VoidResult() { |
| @Override |
| public void run() { |
| final Event event = new Event(); |
| event.time = (int) System.currentTimeMillis(); |
| event.display = control.getDisplay(); |
| event.widget = control; |
| event.x = bounds.x + widget.getTimeDataProvider().getNameSpace() / 2; |
| event.y = bounds.y + bounds.height / 2; |
| control.notifyListeners(SWT.MenuDetect, event); |
| } |
| }); |
| select(); |
| |
| WaitForObjectCondition<Menu> waitForMenu = Conditions.waitForPopupMenu(control); |
| new SWTBot().waitUntilWidgetAppears(waitForMenu); |
| return new SWTBotRootMenu(waitForMenu.get(0)); |
| } |
| |
| /* |
| * Note this is public |
| */ |
| @Override |
| public Rectangle absoluteLocation() { |
| return UIThreadRunnable.syncExec(() -> { |
| Rectangle bounds = widget.getItemBounds(fEntry); |
| if (bounds == null) { |
| return null; |
| } |
| Point location = widget.toDisplay(bounds.x, bounds.y); |
| bounds.x = location.x; |
| bounds.y = location.y; |
| return bounds; |
| }); |
| } |
| |
| /** |
| * Get the child entries of this entry |
| * |
| * @return the array of child entries |
| */ |
| public SWTBotTimeGraphEntry[] getEntries() { |
| return syncExec(new ArrayResult<SWTBotTimeGraphEntry>() { |
| @Override |
| public SWTBotTimeGraphEntry[] run() { |
| List<SWTBotTimeGraphEntry> entries = new ArrayList<>(); |
| for (ITimeGraphEntry entry : widget.getExpandedElements()) { |
| if (fEntry.equals(entry.getParent())) { |
| entries.add(new SWTBotTimeGraphEntry(widget, entry)); |
| } |
| } |
| return entries.toArray(new SWTBotTimeGraphEntry[0]); |
| } |
| }); |
| } |
| |
| /** |
| * Click on the entry at a timestamp |
| * |
| * @param time |
| * the timestamp to click at. |
| */ |
| public void click(long time) { |
| final Point p = getPointForTime(time); |
| if (p == null) { |
| return; |
| } |
| clickXY(p.x, p.y); |
| } |
| |
| /** |
| * Double-click on the entry at a timestamp |
| * |
| * @param time |
| * the timestamp to double-click at. |
| */ |
| public void doubleClick(long time) { |
| final Point p = getPointForTime(time); |
| if (p == null) { |
| return; |
| } |
| doubleClickXY(p.x, p.y); |
| } |
| |
| /** |
| * Get the coordinates of a point for a specified time |
| * |
| * @param time |
| * the time to get the equivalent Point of. |
| * @return the point at the time |
| */ |
| public Point getPointForTime(long time) { |
| return UIThreadRunnable.syncExec((Result<Point>) () -> { |
| ITimeDataProvider timeDataProvider = widget.getTimeDataProvider(); |
| if (timeDataProvider.getTime0() > time || timeDataProvider.getTime1() < time) { |
| return null; |
| } |
| int x = widget.getXForTime(time); |
| Rectangle bounds = widget.getItemBounds(fEntry); |
| int y = bounds.y + bounds.height / 2; |
| return new Point(x, y); |
| }); |
| } |
| |
| /** |
| * Get the time in the entry for a given X point |
| * |
| * @param x |
| * the x point |
| * @return the time or {@code null} or {@code -1} if it is out of bounds |
| */ |
| public Long getTimeForPoint(int x) { |
| return UIThreadRunnable.syncExec((Result<@Nullable Long>) () -> { |
| Rectangle bounds = widget.getBounds(); |
| Point p = new Point(x, bounds.y + bounds.height / 2); |
| if (!bounds.contains(p)) { |
| return null; |
| } |
| return widget.getTimeAtX(x); |
| }); |
| } |
| |
| /** |
| * Get the child entry of this entry with the given name |
| * |
| * @param name |
| * the name of the entry |
| * |
| * @return the child entry |
| */ |
| public SWTBotTimeGraphEntry getEntry(String name) { |
| AtomicReference<ITimeGraphEntry> found = new AtomicReference<>(); |
| SWTBotUtils.waitUntil(timegraph -> { |
| List<ITimeGraphEntry> entries = syncExec(new ListResult<ITimeGraphEntry>() { |
| @Override |
| public List<ITimeGraphEntry> run() { |
| return Arrays.asList(timegraph.getExpandedElements()); |
| } |
| }); |
| ITableLabelProvider labelProvider = timegraph.getLabelProvider(); |
| for (ITimeGraphEntry entry : entries) { |
| if (fEntry.equals(entry.getParent())) { |
| String label = labelProvider == null ? entry.getName() : labelProvider.getColumnText(entry, 0); |
| if (name.equals(label)) { |
| found.set(entry); |
| return true; |
| } |
| } |
| } |
| return false; |
| }, widget, () -> "Timed out waiting for time graph entry " + name); |
| return new SWTBotTimeGraphEntry(widget, found.get()); |
| } |
| |
| /** |
| * Get the text of this entry |
| * |
| * @return the text |
| */ |
| @Override |
| public String getText() { |
| return getText(0); |
| } |
| |
| /** |
| * Get the text of this entry for the given column index |
| * |
| * @param column |
| * the column index |
| * @return the column text |
| */ |
| public String getText(int column) { |
| ITableLabelProvider labelProvider = widget.getLabelProvider(); |
| return labelProvider != null ? labelProvider.getColumnText(fEntry, column) : column == 0 ? fEntry.getName() : ""; |
| } |
| |
| /** |
| * Select this time graph entry |
| * |
| * @return itself |
| */ |
| public SWTBotTimeGraphEntry select() { |
| syncExec(new VoidResult() { |
| @Override |
| public void run() { |
| widget.setFocus(); |
| widget.selectItem(fEntry, false); |
| widget.fireSelectionChanged(); |
| } |
| }); |
| return this; |
| } |
| |
| /** |
| * Expand the time graph entry |
| */ |
| public void expand() { |
| syncExec(() -> widget.setExpandedState(fEntry, true)); |
| } |
| |
| /** |
| * Expand the time graph entry |
| */ |
| public void collapse() { |
| syncExec(() -> widget.setExpandedState(fEntry, false)); |
| } |
| } |