From: Patrick Tasse Date: Thu, 17 Jul 2014 14:43:01 +0000 (-0400) Subject: tmf: Add sort options to Call Stack view X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=46cc1adee1d89b91791e8779e13a9bfdbba04282;p=deliverable%2Ftracecompass.git tmf: Add sort options to Call Stack view Change-Id: Idcfe2b9562c6701d337d5fee1e49d5c8fa6c8de4 Signed-off-by: Patrick Tasse Reviewed-on: https://git.eclipse.org/r/30054 Reviewed-by: Matthew Khouzam Tested-by: Hudson CI --- diff --git a/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_alpha.gif b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_alpha.gif new file mode 100644 index 0000000000..6311cc00f8 Binary files /dev/null and b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_alpha.gif differ diff --git a/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_alpha_rev.gif b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_alpha_rev.gif new file mode 100644 index 0000000000..7503bf11d3 Binary files /dev/null and b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_alpha_rev.gif differ diff --git a/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_num.gif b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_num.gif new file mode 100644 index 0000000000..a889504192 Binary files /dev/null and b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_num.gif differ diff --git a/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_num_rev.gif b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_num_rev.gif new file mode 100644 index 0000000000..2df6cacc16 Binary files /dev/null and b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_num_rev.gif differ diff --git a/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_time.gif b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_time.gif new file mode 100644 index 0000000000..26668c2c16 Binary files /dev/null and b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_time.gif differ diff --git a/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_time_rev.gif b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_time_rev.gif new file mode 100644 index 0000000000..2e7eed0da0 Binary files /dev/null and b/org.eclipse.linuxtools.tmf.ui/icons/etool16/sort_time_rev.gif differ diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java index d4c8f9c26d..dbd57fdb0d 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java @@ -269,7 +269,9 @@ public class Messages extends NLS { public static String CallStackView_ExitTimeColumn; public static String CallStackView_DurationColumn; public static String CallStackView_StackInfoNotAvailable; - + public static String CallStackView_SortByThreadName; + public static String CallStackView_SortByThreadId; + public static String CallStackView_SortByThreadTime; public static String CallStackView_ImportMappingButtonText; public static String CallStackView_ImportMappingButtonTooltip; public static String CallStackView_ImportMappingDialogTitle; diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties index 719385a792..4f766d83ec 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties @@ -269,7 +269,9 @@ CallStackView_EntryTimeColumn=Entry time CallStackView_ExitTimeColumn=Exit time CallStackView_DurationColumn=Duration CallStackView_StackInfoNotAvailable=Stack info not available - +CallStackView_SortByThreadName=Sort threads by thread name +CallStackView_SortByThreadId=Sort threads by thread id +CallStackView_SortByThreadTime=Sort threads by start time CallStackView_ImportMappingButtonText=Import mapping file... CallStackView_ImportMappingButtonTooltip=Import a text file containing the mapping between addresses and function names CallStackView_ImportMappingDialogTitle=Select Mapping File diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/callstack/CallStackView.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/callstack/CallStackView.java index 6db4f0a9a1..037fa65d55 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/callstack/CallStackView.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/callstack/CallStackView.java @@ -15,6 +15,7 @@ package org.eclipse.linuxtools.tmf.ui.views.callstack; import java.io.File; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -30,7 +31,10 @@ import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.DoubleClickEvent; @@ -90,6 +94,8 @@ import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorPart; @@ -113,7 +119,7 @@ public class CallStackView extends TmfView { */ private enum State { IDLE, BUSY, PENDING } - private static final String[] COLUMN_NAMES = new String[] { + private static final String[] COLUMN_TIMES = new String[] { Messages.CallStackView_FunctionColumn, Messages.CallStackView_DepthColumn, Messages.CallStackView_EntryTimeColumn, @@ -137,6 +143,20 @@ public class CallStackView extends TmfView { private static final String IMPORT_MAPPING_ICON_PATH = "icons/etool16/import.gif"; //$NON-NLS-1$ + private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$ + private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$ + private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$ + private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$ + private static final ImageDescriptor SORT_BY_TIME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$ + private static final ImageDescriptor SORT_BY_TIME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$ + private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$ + private enum SortOption { BY_NAME, BY_NAME_REV, BY_ID, BY_ID_REV, BY_TIME, BY_TIME_REV } + private SortOption fSortOption; + private Comparator fThreadComparator = null; + private Action fSortByNameAction; + private Action fSortByIdAction; + private Action fSortByTimeAction; + // ------------------------------------------------------------------------ // Fields // ------------------------------------------------------------------------ @@ -221,11 +241,13 @@ public class CallStackView extends TmfView { private final int fCallStackQuark; // The state system from which this entry comes private final ITmfStateSystem fSS; + // The thread id + private final long fThreadId; - public ThreadEntry(ITmfStateSystem ss, String name, int callStackQuark, long startTime, long endTime) { + public ThreadEntry(ITmfStateSystem ss, String name, long threadId, int callStackQuark, long startTime, long endTime) { super(name, startTime, endTime); fCallStackQuark = callStackQuark; - + fThreadId = threadId; fSS = ss; } @@ -238,12 +260,54 @@ public class CallStackView extends TmfView { return fCallStackQuark; } + public long getThreadId() { + return fThreadId; + } + @Nullable public ITmfStateSystem getStateSystem() { return fSS; } } + private class ThreadNameComparator implements Comparator { + private boolean reverse; + public ThreadNameComparator(boolean reverse) { + this.reverse = reverse; + } + @Override + public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) { + return reverse ? o2.getName().compareTo(o1.getName()) : + o1.getName().compareTo(o2.getName()); + } + } + + private class ThreadIdComparator implements Comparator { + private boolean reverse; + public ThreadIdComparator(boolean reverse) { + this.reverse = reverse; + } + @Override + public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) { + ThreadEntry t1 = (ThreadEntry) o1; + ThreadEntry t2 = (ThreadEntry) o2; + return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) : + Long.compare(t1.getThreadId(), t2.getThreadId()); + } + } + + private class ThreadTimeComparator implements Comparator { + private boolean reverse; + public ThreadTimeComparator(boolean reverse) { + this.reverse = reverse; + } + @Override + public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) { + return reverse ? Long.compare(o2.getStartTime(), o1.getStartTime()) : + Long.compare(o1.getStartTime(), o2.getStartTime()); + } + } + private class TreeContentProvider implements ITreeContentProvider { @Override @@ -443,7 +507,7 @@ public class CallStackView extends TmfView { fTimeGraphCombo.setTreeLabelProvider(new TreeLabelProvider()); - fTimeGraphCombo.setTreeColumns(COLUMN_NAMES); + fTimeGraphCombo.setTreeColumns(COLUMN_TIMES); fTimeGraphCombo.getTreeViewer().getTree().getColumn(0).setWidth(COLUMN_WIDTHS[0]); fTimeGraphCombo.getTreeViewer().getTree().getColumn(1).setWidth(COLUMN_WIDTHS[1]); @@ -535,6 +599,8 @@ public class CallStackView extends TmfView { // View Action Handling makeActions(); contributeToActionBars(); + createContextMenu(); + loadSortOption(); IEditorPart editor = getSite().getPage().getActiveEditor(); if (editor instanceof ITmfTraceEditor) { @@ -757,6 +823,7 @@ public class CallStackView extends TmfView { String[] threadPaths = module.getThreadsPattern(); List threadQuarks = ss.getQuarks(threadPaths); TraceEntry traceEntry = new TraceEntry(trace.getName(), startTime, endTime); + traceEntry.sortChildren(fThreadComparator); entryList.add(traceEntry); for (int i = 0; i < threadQuarks.size(); i++) { if (monitor.isCanceled()) { @@ -767,7 +834,18 @@ public class CallStackView extends TmfView { String[] callStackPath = module.getCallStackPath(); int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath); String threadName = ss.getAttributeName(threadQuark); - ThreadEntry threadEntry = new ThreadEntry(ss, threadName, callStackQuark, startTime, endTime); + long threadId = ss.querySingleState(ss.getCurrentEndTime() , threadQuark).getStateValue().unboxLong(); + long start = startTime; + ITmfStateInterval startInterval = ss.querySingleState(startTime, callStackQuark); + if (startInterval.getStateValue().isNull()) { + start = Math.min(startInterval.getEndTime() + 1, endTime); + } + long end = endTime; + ITmfStateInterval endInterval = ss.querySingleState(ss.getCurrentEndTime(), callStackQuark); + if (endInterval.getStateValue().isNull()) { + end = endInterval.getStartTime() == startTime ? endTime : endInterval.getStartTime(); + } + ThreadEntry threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, start, end); traceEntry.addChild(threadEntry); int level = 1; for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) { @@ -776,6 +854,8 @@ public class CallStackView extends TmfView { } } catch (AttributeNotFoundException e) { Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$ + } catch (StateSystemDisposedException e) { + /* Ignored */ } } } @@ -936,6 +1016,9 @@ public class CallStackView extends TmfView { fEntryList = new ArrayList<>(); } entries = fEntryList.toArray(new ITimeGraphEntry[0]); + for (TraceEntry traceEntry : fEntryList) { + traceEntry.sortChildren(fThreadComparator); + } } fTimeGraphCombo.setInput(entries); fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime); @@ -1026,6 +1109,11 @@ public class CallStackView extends TmfView { private void fillLocalToolBar(IToolBarManager manager) { manager.add(getImportMappingAction()); + manager.add(new Separator()); + manager.add(getSortByNameAction()); + manager.add(getSortByIdAction()); + manager.add(getSortByTimeAction()); + manager.add(new Separator()); manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction()); manager.add(getPreviousEventAction()); manager.add(getNextEventAction()); @@ -1036,6 +1124,17 @@ public class CallStackView extends TmfView { manager.add(new Separator()); } + private void createContextMenu() { + final MenuManager contextMenu = new MenuManager(); + contextMenu.add(getSortByNameAction()); + contextMenu.add(getSortByIdAction()); + contextMenu.add(getSortByTimeAction()); + + Tree tree = fTimeGraphCombo.getTreeViewer().getTree(); + Menu menu = contextMenu.createContextMenu(tree); + tree.setMenu(menu); + } + /** * Get the the next event action. * @@ -1200,6 +1299,120 @@ public class CallStackView extends TmfView { return fImportMappingAction; } + private Action getSortByNameAction() { + if (fSortByNameAction == null) { + fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) { + @Override + public void run() { + if (fSortOption == SortOption.BY_NAME) { + saveSortOption(SortOption.BY_NAME_REV); + } else { + saveSortOption(SortOption.BY_NAME); + } + } + }; + fSortByNameAction.setToolTipText(Messages.CallStackView_SortByThreadName); + } + return fSortByNameAction; + } + + private Action getSortByIdAction() { + if (fSortByIdAction == null) { + fSortByIdAction = new Action(Messages.CallStackView_SortByThreadId, IAction.AS_CHECK_BOX) { + @Override + public void run() { + if (fSortOption == SortOption.BY_ID) { + saveSortOption(SortOption.BY_ID_REV); + } else { + saveSortOption(SortOption.BY_ID); + } + } + }; + fSortByIdAction.setToolTipText(Messages.CallStackView_SortByThreadId); + } + return fSortByIdAction; + } + + private Action getSortByTimeAction() { + if (fSortByTimeAction == null) { + fSortByTimeAction = new Action(Messages.CallStackView_SortByThreadTime, IAction.AS_CHECK_BOX) { + @Override + public void run() { + if (fSortOption == SortOption.BY_TIME) { + saveSortOption(SortOption.BY_TIME_REV); + } else { + saveSortOption(SortOption.BY_TIME); + } + } + }; + fSortByTimeAction.setToolTipText(Messages.CallStackView_SortByThreadTime); + } + return fSortByTimeAction; + } + + private void loadSortOption() { + IDialogSettings settings = Activator.getDefault().getDialogSettings(); + IDialogSettings section = settings.getSection(getClass().getName()); + if (section == null) { + return; + } + String sortOption = section.get(SORT_OPTION_KEY); + + // reset defaults + getSortByNameAction().setChecked(false); + getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON); + getSortByIdAction().setChecked(false); + getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON); + getSortByTimeAction().setChecked(false); + getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON); + + if (sortOption.equals(SortOption.BY_NAME.name())) { + fSortOption = SortOption.BY_NAME; + fThreadComparator = new ThreadNameComparator(false); + getSortByNameAction().setChecked(true); + } else if (sortOption.equals(SortOption.BY_NAME_REV.name())) { + fSortOption = SortOption.BY_NAME_REV; + fThreadComparator = new ThreadNameComparator(true); + getSortByNameAction().setChecked(true); + getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON); + } else if (sortOption.equals(SortOption.BY_ID.name())) { + fSortOption = SortOption.BY_ID; + fThreadComparator = new ThreadIdComparator(false); + getSortByIdAction().setChecked(true); + } else if (sortOption.equals(SortOption.BY_ID_REV.name())) { + fSortOption = SortOption.BY_ID_REV; + fThreadComparator = new ThreadIdComparator(true); + getSortByIdAction().setChecked(true); + getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON); + } else if (sortOption.equals(SortOption.BY_TIME.name())) { + fSortOption = SortOption.BY_TIME; + fThreadComparator = new ThreadTimeComparator(false); + getSortByTimeAction().setChecked(true); + } else if (sortOption.equals(SortOption.BY_TIME_REV.name())) { + fSortOption = SortOption.BY_TIME_REV; + fThreadComparator = new ThreadTimeComparator(true); + getSortByTimeAction().setChecked(true); + getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON); + } + } + + private void saveSortOption(SortOption sortOption) { + IDialogSettings settings = Activator.getDefault().getDialogSettings(); + IDialogSettings section = settings.getSection(getClass().getName()); + if (section == null) { + section = settings.addNewSection(getClass().getName()); + } + section.put(SORT_OPTION_KEY, sortOption.name()); + loadSortOption(); + if (fEntryList == null) { + return; + } + for (TraceEntry traceEntry : fEntryList) { + traceEntry.sortChildren(fThreadComparator); + } + refresh(); + } + private class ImportMappingJob extends Job { private final File fMappingFile;