package com.mobilesorcery.sdk.profiling.ui.views; import java.io.File; import java.util.ArrayList; import java.util.Comparator; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.Path; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.layout.TreeColumnLayout; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TreeColumnViewerLabelProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import com.mobilesorcery.sdk.core.IFilter; import com.mobilesorcery.sdk.core.Util; import com.mobilesorcery.sdk.profiling.IInvocation; import com.mobilesorcery.sdk.profiling.ILocationProvider; import com.mobilesorcery.sdk.profiling.IProfilingSession; import com.mobilesorcery.sdk.ui.UIUtils; public class ProfilingComposite extends Composite { private final class ComparatorViewerSorter extends ViewerSorter { private final Comparator<IInvocation> comparator; private ComparatorViewerSorter(Comparator<IInvocation> comparator, boolean ascending) { this.comparator = ascending ? comparator : Util.reverseComparator(comparator); } public int compare(Viewer viewer, Object o1, Object o2) { return comparator.compare((IInvocation) o1, (IInvocation) o2); } } private TreeViewer profileTreeViewer; private IProfilingSession session; PercentageBarLabelProvider percentageLabelProvider; private FunctionNameLabelProvider functionNameLabelProvider; private ProfilingLabelProvider labelProvider; private IStatusLineManager statusLine; public ProfilingComposite(Composite parent, int style) { super(parent, style); Composite treeContainer = this; TreeColumnLayout layout = new TreeColumnLayout(); treeContainer.setLayout(layout); profileTreeViewer = new TreeViewer(treeContainer, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); Tree profileTree = profileTreeViewer.getTree(); profileTree.setHeaderVisible(true); profileTree.setLinesVisible(true); profileTreeViewer.setContentProvider(new ProfilingContentProvider(isFlat())); profileTreeViewer.setInput(IInvocation.EMPTY); ArrayList<TreeColumn> columns = new ArrayList<TreeColumn>(); labelProvider = new ProfilingLabelProvider(); TreeColumnViewerLabelProvider cellLabelProvider = new TreeColumnViewerLabelProvider(labelProvider); functionNameLabelProvider = new FunctionNameLabelProvider(); percentageLabelProvider = new PercentageBarLabelProvider(!isFlat()); TreeViewerColumn functionNameCol = new TreeViewerColumn(profileTreeViewer, SWT.NONE); functionNameCol.getColumn().setText("Function"); functionNameCol.getColumn().setData(ProfilingLabelProvider.FUNCTION_COL); functionNameCol.setLabelProvider(functionNameLabelProvider); prepareColumn(functionNameCol, IInvocation.SORT_BY_FUNC_NAME); columns.add(functionNameCol.getColumn()); TreeViewerColumn percentageCol = new TreeViewerColumn(profileTreeViewer, SWT.NONE); percentageCol.getColumn().setText("[%]"); percentageCol.getColumn().setData(ProfilingLabelProvider.PERCENTAGE_TIME_COL); percentageCol.getColumn().setAlignment(SWT.RIGHT); percentageCol.setLabelProvider(percentageLabelProvider); prepareColumn(percentageCol, isFlat() ? IInvocation.SORT_BY_SELF_TIME : IInvocation.SORT_BY_AGG_TIME); layout.setColumnData(percentageCol.getColumn(), new ColumnWeightData(1)); columns.add(percentageCol.getColumn()); if (isFlat()) { TreeViewerColumn selfTimeCol = new TreeViewerColumn(profileTreeViewer, SWT.NONE); selfTimeCol.getColumn().setText("Self time"); selfTimeCol.getColumn().setData(ProfilingLabelProvider.SELF_TIME_COL); selfTimeCol.getColumn().setAlignment(SWT.RIGHT); selfTimeCol.setLabelProvider(cellLabelProvider); prepareColumn(selfTimeCol, IInvocation.SORT_BY_SELF_TIME); layout.setColumnData(selfTimeCol.getColumn(), new ColumnWeightData(1)); columns.add(selfTimeCol.getColumn()); } else { TreeViewerColumn aggTimeCol = new TreeViewerColumn(profileTreeViewer, SWT.NONE); aggTimeCol.getColumn().setText("Aggregate time"); aggTimeCol.getColumn().setData(ProfilingLabelProvider.AGG_TIME_COL); aggTimeCol.getColumn().setAlignment(SWT.RIGHT); aggTimeCol.setLabelProvider(cellLabelProvider); prepareColumn(aggTimeCol, IInvocation.SORT_BY_AGG_TIME); layout.setColumnData(aggTimeCol.getColumn(), new ColumnWeightData(1)); columns.add(aggTimeCol.getColumn()); } TreeViewerColumn callsCol = new TreeViewerColumn(profileTreeViewer, SWT.NONE); callsCol.getColumn().setText("Calls"); callsCol.getColumn().setData(ProfilingLabelProvider.CALLS_COL); callsCol.getColumn().setAlignment(SWT.RIGHT); callsCol.setLabelProvider(cellLabelProvider); prepareColumn(callsCol, IInvocation.SORT_BY_INVOCATION_COUNT); columns.add(callsCol.getColumn()); layout.setColumnData(functionNameCol.getColumn(), new ColumnWeightData(3)); layout.setColumnData(callsCol.getColumn(), new ColumnWeightData(1)); labelProvider.setColumns(columns.toArray(new TreeColumn[0])); profileTreeViewer.setFilters(new ViewerFilter[] { new ViewerFilter() { public boolean select(Viewer viewer, Object parentElement, Object element) { IInvocation invocation = (IInvocation) element; return !isFlat() || (session != null && session.getFilter().accept(invocation)); } } }); profileTreeViewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { IStructuredSelection selection = (IStructuredSelection) event.getSelection(); Object element = selection.getFirstElement(); if (element instanceof IInvocation) { IInvocation invocation = (IInvocation) element; String filename = invocation.getProfiledEntity().getFileName(); filename = mapToLocalFilename(filename); int linenumber = invocation.getProfiledEntity().getLineNumber(); if (filename != null && new File(filename).exists()) { UIUtils.openResource(new Path(filename), linenumber); if (statusLine != null) { statusLine.setErrorMessage(null); } } else { if (statusLine != null) { statusLine.setErrorMessage(String.format("Could not open file %s; it does not exist?", filename)); } } } } }); } protected String mapToLocalFilename(String filename) { if (session != null) { ILocationProvider locationProvider = session.getLocationProvider(); IFile workspaceRelativeLocation = locationProvider.getLocation(filename); if (workspaceRelativeLocation != null) { return workspaceRelativeLocation.getLocation().toOSString(); } } return filename; } public void setStatusLineManager(IStatusLineManager statusLine) { this.statusLine = statusLine; } public boolean isFlat() { return (getStyle() & SWT.FLAT) != 0; } private void prepareColumn(final TreeViewerColumn functionNameCol, final Comparator<IInvocation> comparator) { //if (isFlat()) { functionNameCol.getColumn().addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { int sortDir = SWT.DOWN; if (profileTreeViewer.getTree().getSortColumn() == functionNameCol.getColumn()) { sortDir = profileTreeViewer.getTree().getSortDirection() == SWT.UP ? SWT.DOWN : SWT.UP; } profileTreeViewer.getTree().setSortColumn(functionNameCol.getColumn()); profileTreeViewer.getTree().setSortDirection(sortDir); profileTreeViewer.setSorter(new ComparatorViewerSorter(comparator, sortDir == SWT.UP)); profileTreeViewer.refresh(); } }); //} } public boolean setFocus() { return profileTreeViewer.getControl().setFocus(); } public TreeViewer getViewer() { return profileTreeViewer; } public void setInput(IProfilingSession session) { this.session = session; functionNameLabelProvider.setSession(session); percentageLabelProvider.setSession(session); labelProvider.setSession(session); profileTreeViewer.setInput(session); } public void setFilter(IFilter<IInvocation> filter, boolean recursive) { profileTreeViewer.setFilters(new ViewerFilter[] { new InvocationViewerFilter(filter, recursive) }); } }