/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ddmuilib; import com.android.ddmlib.Client; import com.android.ddmlib.IStackTraceInfo; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; /** * Stack Trace Panel. * <p/>This is not a panel in the regular sense. Instead this is just an object around the creation * and management of a Stack Trace display. * <p/>UI creation is done through * {@link #createPanel(Composite, String, String, String, String, String, IPreferenceStore)}. * */ public final class StackTracePanel { private static ISourceRevealer sSourceRevealer; private Table mStackTraceTable; private TableViewer mStackTraceViewer; private Client mCurrentClient; /** * Content Provider to display the stack trace of a thread. * Expected input is a {@link IStackTraceInfo} object. */ private static class StackTraceContentProvider implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { if (inputElement instanceof IStackTraceInfo) { // getElement cannot return null, so we return an empty array // if there's no stack trace StackTraceElement trace[] = ((IStackTraceInfo)inputElement).getStackTrace(); if (trace != null) { return trace; } } return new Object[0]; } public void dispose() { // pass } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // pass } } /** * A Label Provider to use with {@link StackTraceContentProvider}. It expects the elements to be * of type {@link StackTraceElement}. */ private static class StackTraceLabelProvider implements ITableLabelProvider { public Image getColumnImage(Object element, int columnIndex) { return null; } public String getColumnText(Object element, int columnIndex) { if (element instanceof StackTraceElement) { StackTraceElement traceElement = (StackTraceElement)element; switch (columnIndex) { case 0: return traceElement.getClassName(); case 1: return traceElement.getMethodName(); case 2: return traceElement.getFileName(); case 3: return Integer.toString(traceElement.getLineNumber()); case 4: return Boolean.toString(traceElement.isNativeMethod()); } } return null; } public void addListener(ILabelProviderListener listener) { // pass } public void dispose() { // pass } public boolean isLabelProperty(Object element, String property) { // pass return false; } public void removeListener(ILabelProviderListener listener) { // pass } } /** * Classes which implement this interface provide a method that is able to reveal a method * in a source editor */ public interface ISourceRevealer { /** * Sent to reveal a particular line in a source editor * @param applicationName the name of the application running the source. * @param className the fully qualified class name * @param line the line to reveal */ public void reveal(String applicationName, String className, int line); } /** * Sets the {@link ISourceRevealer} object able to reveal source code in a source editor. * @param revealer */ public static void setSourceRevealer(ISourceRevealer revealer) { sSourceRevealer = revealer; } /** * Creates the controls for the StrackTrace display. * <p/>This method will set the parent {@link Composite} to use a {@link GridLayout} with * 2 columns. * @param parent the parent composite. * @param prefs_stack_col_class * @param prefs_stack_col_method * @param prefs_stack_col_file * @param prefs_stack_col_line * @param prefs_stack_col_native * @param store */ public Table createPanel(Composite parent, String prefs_stack_col_class, String prefs_stack_col_method, String prefs_stack_col_file, String prefs_stack_col_line, String prefs_stack_col_native, IPreferenceStore store) { mStackTraceTable = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION); mStackTraceTable.setHeaderVisible(true); mStackTraceTable.setLinesVisible(true); TableHelper.createTableColumn( mStackTraceTable, "Class", SWT.LEFT, "SomeLongClassName", //$NON-NLS-1$ prefs_stack_col_class, store); TableHelper.createTableColumn( mStackTraceTable, "Method", SWT.LEFT, "someLongMethod", //$NON-NLS-1$ prefs_stack_col_method, store); TableHelper.createTableColumn( mStackTraceTable, "File", SWT.LEFT, "android/somepackage/someotherpackage/somefile.class", //$NON-NLS-1$ prefs_stack_col_file, store); TableHelper.createTableColumn( mStackTraceTable, "Line", SWT.RIGHT, "99999", //$NON-NLS-1$ prefs_stack_col_line, store); TableHelper.createTableColumn( mStackTraceTable, "Native", SWT.LEFT, "Native", //$NON-NLS-1$ prefs_stack_col_native, store); mStackTraceViewer = new TableViewer(mStackTraceTable); mStackTraceViewer.setContentProvider(new StackTraceContentProvider()); mStackTraceViewer.setLabelProvider(new StackTraceLabelProvider()); mStackTraceViewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { if (sSourceRevealer != null && mCurrentClient != null) { // get the selected stack trace element ISelection selection = mStackTraceViewer.getSelection(); if (selection instanceof IStructuredSelection) { IStructuredSelection structuredSelection = (IStructuredSelection)selection; Object object = structuredSelection.getFirstElement(); if (object instanceof StackTraceElement) { StackTraceElement traceElement = (StackTraceElement)object; if (traceElement.isNativeMethod() == false) { sSourceRevealer.reveal( mCurrentClient.getClientData().getClientDescription(), traceElement.getClassName(), traceElement.getLineNumber()); } } } } } }); return mStackTraceTable; } /** * Sets the input for the {@link TableViewer}. * @param input the {@link IStackTraceInfo} that will provide the viewer with the list of * {@link StackTraceElement} */ public void setViewerInput(IStackTraceInfo input) { mStackTraceViewer.setInput(input); mStackTraceViewer.refresh(); } /** * Sets the current client running the stack trace. * @param currentClient the {@link Client}. */ public void setCurrentClient(Client currentClient) { mCurrentClient = currentClient; } }