/*******************************************************************************
* Copyright (c) 2010, 2014 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Patrick Tasse - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.tmf.ui.views.timechart;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
/**
* Event in the time chart view
*
* @version 1.0
* @author Patrick Tasse
*/
public class TimeChartEvent implements ITimeEvent {
private final TimeChartAnalysisEntry fParentEntry;
private long fTime;
private long fDuration;
private long fFirstRank;
private long fLastRank;
private final RankRangeList fRankRangeList;
private long fNbEvents;
private int fColorSettingPriority;
private boolean fIsBookmark;
private boolean fIsVisible;
private boolean fIsSearchMatch;
private TimeChartAnalysisEntry fItemizedEntry;
private boolean fItemizing;
/**
* Standard constructor
*
* @param parentEntry
* The parent entry
* @param event
* The event from which this time chart event originates
* @param rank
* The rank of the event in the trace
* @param decorationProvider
* The decoration provider to use
*/
public TimeChartEvent(TimeChartAnalysisEntry parentEntry, ITmfEvent event,
long rank, TimeChartDecorationProvider decorationProvider) {
fParentEntry = parentEntry;
fTime = event.getTimestamp().toNanos();
fDuration = 0;
fFirstRank = fLastRank = rank;
fRankRangeList = new RankRangeList(rank);
fNbEvents = 1;
fColorSettingPriority = ColorSettingsManager.getColorSettingPriority(event);
fIsBookmark = decorationProvider.isBookmark(rank);
fIsVisible = decorationProvider.isVisible(event);
fIsSearchMatch = decorationProvider.isSearchMatch(event);
}
@Override
public ITimeGraphEntry getEntry() {
return fParentEntry;
}
@Override
public long getTime() {
return fTime;
}
@Override
public long getDuration() {
return fDuration;
}
@Override
public ITimeEvent splitBefore(long splitTime) {
return (splitTime > fTime ?
new TimeEvent(getEntry(), fTime, Math.min(fDuration, splitTime - fTime)) :
null);
}
@Override
public ITimeEvent splitAfter(long splitTime) {
return (splitTime < fTime + fDuration ?
new TimeEvent(getEntry(), Math.max(fTime, splitTime), fDuration - Math.max(0, splitTime - fTime)) :
null);
}
/**
* Retrieve the rank of the trace event which started this time event.
*
* @return The rank of the beginning
*/
public long getFirstRank() {
return fFirstRank;
}
/**
* Retrieve the rank of the trace event which *finished* this time event.
*
* @return The rank of the end
*/
public long getLastRank() {
return fLastRank;
}
/**
* Get the list of rank ranges corresponding to this time event.
*
* @return The rank range list
*/
public RankRangeList getRankRangeList() {
return fRankRangeList;
}
/**
* Merge another time event with this one.
*
* @param event
* The other event
*/
public void merge(TimeChartEvent event) {
mergeDecorations(event);
if (fTime == event.getTime() && fDuration == event.getDuration()) {
return;
}
long endTime = Math.max(fTime + fDuration, event.getTime() + event.getDuration());
fTime = Math.min(fTime, event.getTime());
fDuration = endTime - fTime;
fFirstRank = Math.min(fFirstRank, event.fFirstRank);
fLastRank = Math.max(fLastRank, event.fLastRank);
fNbEvents += event.fNbEvents;
fItemizedEntry = null;
synchronized (fRankRangeList) {
fRankRangeList.merge(event.getRankRangeList());
}
}
/**
* Merge the decorations of another time event with the decorations of this
* one.
*
* @param event
* The other event
*/
public void mergeDecorations(TimeChartEvent event) {
fColorSettingPriority = Math.min(fColorSettingPriority, event.getColorSettingPriority());
fIsBookmark |= event.fIsBookmark;
fIsVisible |= event.fIsVisible;
fIsSearchMatch |= event.fIsSearchMatch;
}
/**
* Get the number of time events that have been merged with this one (starts
* counting at 1 if no merge happened).
*
* @return The current number of events in the bath
*/
public long getNbEvents() {
return fNbEvents;
}
/**
* Retrieve the color setting priority.
*
* @return The priority
*/
public int getColorSettingPriority() {
return fColorSettingPriority;
}
/**
* Set the color setting priority.
*
* @param priority
* The priority to set
*/
public void setColorSettingPriority(int priority) {
fColorSettingPriority = priority;
}
/**
* Check if this time event is bookmarked
*
* @return Y/N
*/
public boolean isBookmarked() {
return fIsBookmark;
}
/**
* Set this time event to be bookmarked or not.
*
* @param isBookmarked
* Should time time event become a bookmark, or not
*/
public void setIsBookmarked(boolean isBookmarked) {
fIsBookmark = isBookmarked;
}
/**
* Check if this time is currently visible or not.
*
* @return If the event is visible
*/
public boolean isVisible() {
return fIsVisible;
}
/**
* Set this time event to visible (or to non-visible).
*
* @param isVisible The new status
*/
public void setIsVisible(boolean isVisible) {
fIsVisible = isVisible;
}
/**
* Check if the time event matches the current search.
*
* @return If it matches, Y/N
*/
public boolean isSearchMatch() {
return fIsSearchMatch;
}
/**
* Mark this event as matching (or non-matching) the current search.
*
* @param isSearchMatch
* The new matching status
*/
public void setIsSearchMatch(boolean isSearchMatch) {
fIsSearchMatch = isSearchMatch;
}
/**
* Set this event's itemized entry.
*
* @param timeAnalysisEntry
* The entry to set
*/
public void setItemizedEntry(TimeChartAnalysisEntry timeAnalysisEntry) {
fItemizedEntry = timeAnalysisEntry;
}
/**
* Retrieve this event's itemized entry.
*
* @return The itemized entry that was previously set
*/
public TimeChartAnalysisEntry getItemizedEntry() {
return fItemizedEntry;
}
/**
* @return Has this time event been set to itemizing?
*/
public boolean isItemizing() {
return fItemizing;
}
/**
* Set this event's itemizing flag to true or false.
*
* @param itemizing
* The new value
*/
public void setItemizing(boolean itemizing) {
fItemizing = itemizing;
}
/**
* Inner class to define a range in terms of ranks in the trace.
*
* @version 1.0
* @author Patrick Tasse
*/
public class RankRange {
private long firstRank;
private long lastRank;
/**
* Standard constructor
*
* @param firstRank
* The first (earliest) rank of the range
* @param lastRank
* The last (latest) rank of the range
*/
public RankRange(long firstRank, long lastRank) {
this.firstRank = firstRank;
this.lastRank = lastRank;
}
/**
* Retrieve the start rank of this range.
*
* @return The first rank
*/
public long getFirstRank() {
return firstRank;
}
/**
* Retrieve the end rank of this range
*
* @return The end rank
*/
public long getLastRank() {
return lastRank;
}
/**
* Calculate the minimal distance between two RankRange's
*
* @param range
* The other range
* @return The distance, in "number of events" between the two ranges
*/
public long distanceFrom(RankRange range) {
if (range.lastRank < fFirstRank) {
return fFirstRank - range.lastRank;
} else if (range.firstRank > fLastRank) {
return range.firstRank - fLastRank;
} else {
return 0;
}
}
@Override
public String toString() {
return "["+firstRank+","+lastRank+"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
private class RankRangeList extends ArrayList<RankRange> {
private static final long serialVersionUID = 6060485531208535986L;
public RankRangeList(long rank) {
super(1);
add(new RankRange(rank, rank));
}
public void merge(RankRangeList rankRangeList) {
long threshold = fParentEntry.getTrace().getCacheSize();
for (RankRange newRange : rankRangeList) {
boolean merged = false;
for (RankRange oldRange : fRankRangeList) {
if (newRange.distanceFrom(oldRange) <= threshold) {
oldRange.firstRank = Math.min(oldRange.firstRank, newRange.firstRank);
oldRange.lastRank = Math.max(oldRange.lastRank, newRange.lastRank);
merged = true;
break;
}
}
if (!merged) {
add(newRange);
}
}
Iterator<RankRange> iterator = fRankRangeList.iterator();
RankRange previous = null;
while (iterator.hasNext()) {
RankRange range = iterator.next();
if (previous != null && range.distanceFrom(previous) <= threshold) {
previous.firstRank = Math.min(previous.firstRank, range.firstRank);
previous.lastRank = Math.max(previous.lastRank, range.lastRank);
iterator.remove();
}
previous = range;
}
}
}
}