1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ddmuilib; 18 19 import com.android.ddmlib.Client; 20 import com.android.ddmlib.IStackTraceInfo; 21 22 import org.eclipse.jface.preference.IPreferenceStore; 23 import org.eclipse.jface.viewers.DoubleClickEvent; 24 import org.eclipse.jface.viewers.IDoubleClickListener; 25 import org.eclipse.jface.viewers.ILabelProviderListener; 26 import org.eclipse.jface.viewers.ISelection; 27 import org.eclipse.jface.viewers.IStructuredContentProvider; 28 import org.eclipse.jface.viewers.IStructuredSelection; 29 import org.eclipse.jface.viewers.ITableLabelProvider; 30 import org.eclipse.jface.viewers.TableViewer; 31 import org.eclipse.jface.viewers.Viewer; 32 import org.eclipse.swt.SWT; 33 import org.eclipse.swt.graphics.Image; 34 import org.eclipse.swt.layout.GridLayout; 35 import org.eclipse.swt.widgets.Composite; 36 import org.eclipse.swt.widgets.Table; 37 38 /** 39 * Stack Trace Panel. 40 * <p/>This is not a panel in the regular sense. Instead this is just an object around the creation 41 * and management of a Stack Trace display. 42 * <p/>UI creation is done through 43 * {@link #createPanel(Composite, String, String, String, String, String, IPreferenceStore)}. 44 * 45 */ 46 public final class StackTracePanel { 47 48 private static ISourceRevealer sSourceRevealer; 49 50 private Table mStackTraceTable; 51 private TableViewer mStackTraceViewer; 52 53 private Client mCurrentClient; 54 55 56 /** 57 * Content Provider to display the stack trace of a thread. 58 * Expected input is a {@link IStackTraceInfo} object. 59 */ 60 private static class StackTraceContentProvider implements IStructuredContentProvider { 61 @Override getElements(Object inputElement)62 public Object[] getElements(Object inputElement) { 63 if (inputElement instanceof IStackTraceInfo) { 64 // getElement cannot return null, so we return an empty array 65 // if there's no stack trace 66 StackTraceElement trace[] = ((IStackTraceInfo)inputElement).getStackTrace(); 67 if (trace != null) { 68 return trace; 69 } 70 } 71 72 return new Object[0]; 73 } 74 75 @Override dispose()76 public void dispose() { 77 // pass 78 } 79 80 @Override inputChanged(Viewer viewer, Object oldInput, Object newInput)81 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 82 // pass 83 } 84 } 85 86 87 /** 88 * A Label Provider to use with {@link StackTraceContentProvider}. It expects the elements to be 89 * of type {@link StackTraceElement}. 90 */ 91 private static class StackTraceLabelProvider implements ITableLabelProvider { 92 93 @Override getColumnImage(Object element, int columnIndex)94 public Image getColumnImage(Object element, int columnIndex) { 95 return null; 96 } 97 98 @Override getColumnText(Object element, int columnIndex)99 public String getColumnText(Object element, int columnIndex) { 100 if (element instanceof StackTraceElement) { 101 StackTraceElement traceElement = (StackTraceElement)element; 102 switch (columnIndex) { 103 case 0: 104 return traceElement.getClassName(); 105 case 1: 106 return traceElement.getMethodName(); 107 case 2: 108 return traceElement.getFileName(); 109 case 3: 110 return Integer.toString(traceElement.getLineNumber()); 111 case 4: 112 return Boolean.toString(traceElement.isNativeMethod()); 113 } 114 } 115 116 return null; 117 } 118 119 @Override addListener(ILabelProviderListener listener)120 public void addListener(ILabelProviderListener listener) { 121 // pass 122 } 123 124 @Override dispose()125 public void dispose() { 126 // pass 127 } 128 129 @Override isLabelProperty(Object element, String property)130 public boolean isLabelProperty(Object element, String property) { 131 // pass 132 return false; 133 } 134 135 @Override removeListener(ILabelProviderListener listener)136 public void removeListener(ILabelProviderListener listener) { 137 // pass 138 } 139 } 140 141 /** 142 * Classes which implement this interface provide a method that is able to reveal a method 143 * in a source editor 144 */ 145 public interface ISourceRevealer { 146 /** 147 * Sent to reveal a particular line in a source editor 148 * @param applicationName the name of the application running the source. 149 * @param className the fully qualified class name 150 * @param line the line to reveal 151 */ reveal(String applicationName, String className, int line)152 public void reveal(String applicationName, String className, int line); 153 } 154 155 156 /** 157 * Sets the {@link ISourceRevealer} object able to reveal source code in a source editor. 158 * @param revealer 159 */ setSourceRevealer(ISourceRevealer revealer)160 public static void setSourceRevealer(ISourceRevealer revealer) { 161 sSourceRevealer = revealer; 162 } 163 164 /** 165 * Creates the controls for the StrackTrace display. 166 * <p/>This method will set the parent {@link Composite} to use a {@link GridLayout} with 167 * 2 columns. 168 * @param parent the parent composite. 169 * @param prefs_stack_col_class 170 * @param prefs_stack_col_method 171 * @param prefs_stack_col_file 172 * @param prefs_stack_col_line 173 * @param prefs_stack_col_native 174 * @param store 175 */ 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)176 public Table createPanel(Composite parent, String prefs_stack_col_class, 177 String prefs_stack_col_method, String prefs_stack_col_file, String prefs_stack_col_line, 178 String prefs_stack_col_native, IPreferenceStore store) { 179 180 mStackTraceTable = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION); 181 mStackTraceTable.setHeaderVisible(true); 182 mStackTraceTable.setLinesVisible(true); 183 184 TableHelper.createTableColumn( 185 mStackTraceTable, 186 "Class", 187 SWT.LEFT, 188 "SomeLongClassName", //$NON-NLS-1$ 189 prefs_stack_col_class, store); 190 191 TableHelper.createTableColumn( 192 mStackTraceTable, 193 "Method", 194 SWT.LEFT, 195 "someLongMethod", //$NON-NLS-1$ 196 prefs_stack_col_method, store); 197 198 TableHelper.createTableColumn( 199 mStackTraceTable, 200 "File", 201 SWT.LEFT, 202 "android/somepackage/someotherpackage/somefile.class", //$NON-NLS-1$ 203 prefs_stack_col_file, store); 204 205 TableHelper.createTableColumn( 206 mStackTraceTable, 207 "Line", 208 SWT.RIGHT, 209 "99999", //$NON-NLS-1$ 210 prefs_stack_col_line, store); 211 212 TableHelper.createTableColumn( 213 mStackTraceTable, 214 "Native", 215 SWT.LEFT, 216 "Native", //$NON-NLS-1$ 217 prefs_stack_col_native, store); 218 219 mStackTraceViewer = new TableViewer(mStackTraceTable); 220 mStackTraceViewer.setContentProvider(new StackTraceContentProvider()); 221 mStackTraceViewer.setLabelProvider(new StackTraceLabelProvider()); 222 223 mStackTraceViewer.addDoubleClickListener(new IDoubleClickListener() { 224 @Override 225 public void doubleClick(DoubleClickEvent event) { 226 if (sSourceRevealer != null && mCurrentClient != null) { 227 // get the selected stack trace element 228 ISelection selection = mStackTraceViewer.getSelection(); 229 230 if (selection instanceof IStructuredSelection) { 231 IStructuredSelection structuredSelection = (IStructuredSelection)selection; 232 Object object = structuredSelection.getFirstElement(); 233 if (object instanceof StackTraceElement) { 234 StackTraceElement traceElement = (StackTraceElement)object; 235 236 if (traceElement.isNativeMethod() == false) { 237 sSourceRevealer.reveal( 238 mCurrentClient.getClientData().getClientDescription(), 239 traceElement.getClassName(), 240 traceElement.getLineNumber()); 241 } 242 } 243 } 244 } 245 } 246 }); 247 248 return mStackTraceTable; 249 } 250 251 /** 252 * Sets the input for the {@link TableViewer}. 253 * @param input the {@link IStackTraceInfo} that will provide the viewer with the list of 254 * {@link StackTraceElement} 255 */ setViewerInput(IStackTraceInfo input)256 public void setViewerInput(IStackTraceInfo input) { 257 mStackTraceViewer.setInput(input); 258 mStackTraceViewer.refresh(); 259 } 260 261 /** 262 * Sets the current client running the stack trace. 263 * @param currentClient the {@link Client}. 264 */ setCurrentClient(Client currentClient)265 public void setCurrentClient(Client currentClient) { 266 mCurrentClient = currentClient; 267 } 268 } 269