use of org.lttng.scope.views.timeline.widgets.timegraph.StateRectangle in project lttng-scope by lttng.
the class TimeGraphStateLayer method prepareTimeGrahLabelsContents.
private Node prepareTimeGrahLabelsContents(Collection<StateRectangle> stateRectangles, TimeRange windowRange) {
double minX = getWidget().timestampToPaneXPos(windowRange.getStartTime());
final String ellipsisStr = DebugOptions.ELLIPSIS_STRING;
final double ellipsisWidth = getWidget().getDebugOptions().getEllipsisWidth();
final Font textFont = getWidget().getDebugOptions().stateLabelFont.get();
final OverrunStyle overrunStyle = OverrunStyle.ELLIPSIS;
final Color textColor = Color.WHITE;
/* Requires a ~2 pixels adjustment to be centered on the states */
final double yOffset = TimeGraphWidget.ENTRY_HEIGHT / 2.0 + 2.0;
Collection<Node> texts = stateRectangles.stream().filter(stateRect -> stateRect.getWidth() > ellipsisWidth).filter(stateRect -> stateRect.getStateInterval().getLabel() != null).map(stateRect -> {
String labelText = requireNonNull(stateRect.getStateInterval().getLabel());
/* A small offset looks better here */
double textX = Math.max(minX, stateRect.getX()) + 4.0;
double textY = stateRect.getY() + yOffset;
double rectEndX = stateRect.getX() + stateRect.getWidth();
double minWidth = rectEndX - textX;
String ellipsedText = JfxTextUtils.computeClippedText(textFont, labelText, minWidth, overrunStyle, ellipsisStr);
if (ellipsedText.equals(ellipsisStr)) {
return null;
}
Text text = new Text(textX, textY, ellipsedText);
text.setFont(textFont);
text.setFill(textColor);
return text;
}).filter(Objects::nonNull).collect(Collectors.toList());
return new Group(texts);
}
use of org.lttng.scope.views.timeline.widgets.timegraph.StateRectangle in project lttng-scope by lttng.
the class TimeGraphStateLayer method drawContents.
@Override
public void drawContents(TimeGraphTreeRender treeRender, TimeRange timeRange, VerticalPosition vPos, @Nullable FutureTask<?> task) {
final long resolution = Math.max(1, Math.round(getWidget().getCurrentNanosPerPixel()));
final List<TimeGraphTreeElement> allTreeElements = treeRender.getAllTreeElements();
final int nbElements = allTreeElements.size();
final int entriesToPrefetch = getWidget().getDebugOptions().entryPadding.get();
final int topEntry = Math.max(0, TimeGraphWidget.paneYPosToEntryListIndex(vPos.fTopPos, TimeGraphWidget.ENTRY_HEIGHT) - entriesToPrefetch);
final int bottomEntry = Math.min(nbElements, TimeGraphWidget.paneYPosToEntryListIndex(vPos.fBottomPos, TimeGraphWidget.ENTRY_HEIGHT) + entriesToPrefetch);
LOGGER.finest(() -> "topEntry=" + topEntry + ", bottomEntry=" + bottomEntry);
List<TimeGraphStateRender> stateRenders = allTreeElements.subList(topEntry, bottomEntry).stream().map(treeElem -> fStateProvider.getStateRender(treeElem, timeRange, resolution, task)).collect(Collectors.toList());
if (task != null && task.isCancelled()) {
return;
}
Collection<StateRectangle> stateRectangles = prepareStateRectangles(stateRenders, topEntry);
Node statesLayerContents = prepareTimeGraphStatesContents(stateRectangles);
Node labelsLayerContents = prepareTimeGrahLabelsContents(stateRectangles, fWindowRange);
/*
* Go over all state rectangles, and bring the "multi-state"
* ones to the front, to be sure they show on top of the others.
* Note we cannot do the forEach() as part of the stream, that
* would throw a ConcurrentModificationException.
*/
((Group) statesLayerContents).getChildren().stream().map(node -> (StateRectangle) node).filter(rect -> (rect.getStateInterval().isMultiState())).collect(Collectors.toList()).forEach(Node::toFront);
Platform.runLater(() -> {
getParentGroup().getChildren().clear();
getLabelGroup().getChildren().clear();
getParentGroup().getChildren().add(statesLayerContents);
getLabelGroup().getChildren().add(labelsLayerContents);
});
}
use of org.lttng.scope.views.timeline.widgets.timegraph.StateRectangle in project lttng-scope by lttng.
the class ViewerToolBar method getStateInfoButton.
// FIXME Temporary, should be moved to tooltip
private Button getStateInfoButton(TimeGraphWidget viewer) {
Button button = new Button();
Image helpIcon = JfxImageFactory.getImageFromResource(HELP_ICON_PATH);
button.setGraphic(new ImageView(helpIcon));
// $NON-NLS-1$
button.setTooltip(new Tooltip("Get State Info"));
button.setOnAction(e -> {
StateRectangle state = viewer.getSelectedState();
if (state == null) {
return;
}
Alert alert = new Alert(AlertType.INFORMATION);
/* Use a read-only TextField so the text can be copy-pasted */
TextField content = new TextField(state.toString());
content.setEditable(false);
content.setPrefWidth(1000.0);
alert.getDialogPane().setContent(content);
alert.setResizable(true);
alert.show();
JfxUtils.centerDialogOnScreen(alert, this);
});
return button;
}
use of org.lttng.scope.views.timeline.widgets.timegraph.StateRectangle in project lttng-scope by lttng.
the class NavigationModeFollowEvents method navigate.
private static void navigate(TimeGraphWidget viewer, boolean forward) {
StateRectangle state = viewer.getSelectedState();
TraceProject<?, ?> project = viewer.getControl().getViewContext().getTraceProject();
if (state == null || project == null) {
return;
}
Predicate<TraceEvent> predicate = state.getStateInterval().getTreeElement().getEventMatching();
if (predicate == null) {
/* The tree element does not support navigating by events. */
return;
}
// TODO Reimplement outside of TMF
// String jobName = (forward ? Messages.sfNextEventJobName : Messages.sfPreviousEventJobName);
//
// Job job = new Job(jobName) {
// @Override
// protected IStatus run(@Nullable IProgressMonitor monitor) {
// long currentTime = TmfTraceManager.getInstance().getCurrentTraceContext().getSelectionRange().getStartTime().toNanos();
// ITmfContext ctx = trace.seekEvent(TmfTimestamp.fromNanos(currentTime));
// long rank = ctx.getRank();
// ctx.dispose();
//
// ITmfEvent event = (forward ?
// TmfTraceUtils.getNextEventMatching(trace, rank, predicate, monitor) :
// TmfTraceUtils.getPreviousEventMatching(trace, rank, predicate, monitor));
// if (event != null) {
// NavUtils.selectNewTimestamp(viewer, event.getTimestamp().toNanos());
// }
// return Status.OK_STATUS;
// }
// };
//
// /*
// * Make subsequent jobs not run concurrently, but wait after one
// * another.
// */
// job.setRule(fSearchActionMutexRule);
// job.schedule();
}
use of org.lttng.scope.views.timeline.widgets.timegraph.StateRectangle in project lttng-scope by lttng.
the class NavigationModeFollowStateChanges method navigate.
private static void navigate(TimeGraphWidget viewer, boolean forward) {
StateRectangle state = viewer.getSelectedState();
if (state == null) {
return;
}
long stateStartTime = state.getStateInterval().getStartEvent().getTimestamp();
long stateEndTime = state.getStateInterval().getEndEvent().getTimestamp();
/* Aim to go to the start/end of the next/previous interval */
long targetTimestamp = (forward ? stateEndTime + 1 : stateStartTime - 1);
TimeGraphTreeElement treeElement = state.getStateInterval().getStartEvent().getTreeElement();
List<StateRectangle> potentialStates = getPotentialStates(viewer, targetTimestamp, treeElement, forward);
if (potentialStates.isEmpty()) {
/*
* We either reached the end of our model or an edge of the trace.
* Go to the end/start of the current state.
*/
long bound = (forward ? stateEndTime : stateStartTime);
NavUtils.selectNewTimestamp(viewer, bound);
return;
}
/*
* Also compute the intervals that intersect the target timestamp.
* We will prefer those, but if there aren't any, we'll pick the
* best "potential" state.
*/
List<StateRectangle> intersectingStates = getIntersectingStates(potentialStates, targetTimestamp, forward);
StateRectangle newState;
if (intersectingStates.isEmpty()) {
/*
* Let's look back into 'potentialStates' (non-intersecting)
* and pick the interval with the closest bound.
*/
Optional<StateRectangle> optState = getBestPotentialState(potentialStates, forward);
if (!optState.isPresent()) {
/* We did our best and didn't find anything. */
return;
}
newState = optState.get();
} else if (intersectingStates.size() == 1) {
/* There is only one match, must be the right one. */
newState = intersectingStates.get(0);
} else {
/*
* There is more than one match (overlapping intervals, can
* happen sometimes with multi-states). Pick the one with the
* earliest start time (for backwards) or latest end time (for
* forwards), to ensure we "move out" on the next action.
*/
newState = intersectingStates.stream().sorted(forward ? LATEST_END_TIME_COMPARATOR : EARLIEST_START_TIME_COMPARATOR).findFirst().get();
}
viewer.setSelectedState(newState, true);
newState.showTooltip(forward);
NavUtils.selectNewTimestamp(viewer, targetTimestamp);
}
Aggregations