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 public Object[] getElements(Object inputElement) { 62 if (inputElement instanceof IStackTraceInfo) { 63 // getElement cannot return null, so we return an empty array 64 // if there's no stack trace 65 StackTraceElement trace[] = ((IStackTraceInfo)inputElement).getStackTrace(); 66 if (trace != null) { 67 return trace; 68 } 69 } 70 71 return new Object[0]; 72 } 73 74 public void dispose() { 75 // pass 76 } 77 78 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 79 // pass 80 } 81 } 82 83 84 /** 85 * A Label Provider to use with {@link StackTraceContentProvider}. It expects the elements to be 86 * of type {@link StackTraceElement}. 87 */ 88 private static class StackTraceLabelProvider implements ITableLabelProvider { 89 90 public Image getColumnImage(Object element, int columnIndex) { 91 return null; 92 } 93 94 public String getColumnText(Object element, int columnIndex) { 95 if (element instanceof StackTraceElement) { 96 StackTraceElement traceElement = (StackTraceElement)element; 97 switch (columnIndex) { 98 case 0: 99 return traceElement.getClassName(); 100 case 1: 101 return traceElement.getMethodName(); 102 case 2: 103 return traceElement.getFileName(); 104 case 3: 105 return Integer.toString(traceElement.getLineNumber()); 106 case 4: 107 return Boolean.toString(traceElement.isNativeMethod()); 108 } 109 } 110 111 return null; 112 } 113 114 public void addListener(ILabelProviderListener listener) { 115 // pass 116 } 117 118 public void dispose() { 119 // pass 120 } 121 122 public boolean isLabelProperty(Object element, String property) { 123 // pass 124 return false; 125 } 126 127 public void removeListener(ILabelProviderListener listener) { 128 // pass 129 } 130 } 131 132 /** 133 * Classes which implement this interface provide a method that is able to reveal a method 134 * in a source editor 135 */ 136 public interface ISourceRevealer { 137 /** 138 * Sent to reveal a particular line in a source editor 139 * @param applicationName the name of the application running the source. 140 * @param className the fully qualified class name 141 * @param line the line to reveal 142 */ 143 public void reveal(String applicationName, String className, int line); 144 } 145 146 147 /** 148 * Sets the {@link ISourceRevealer} object able to reveal source code in a source editor. 149 * @param revealer 150 */ 151 public static void setSourceRevealer(ISourceRevealer revealer) { 152 sSourceRevealer = revealer; 153 } 154 155 /** 156 * Creates the controls for the StrackTrace display. 157 * <p/>This method will set the parent {@link Composite} to use a {@link GridLayout} with 158 * 2 columns. 159 * @param parent the parent composite. 160 * @param prefs_stack_col_class 161 * @param prefs_stack_col_method 162 * @param prefs_stack_col_file 163 * @param prefs_stack_col_line 164 * @param prefs_stack_col_native 165 * @param store 166 */ 167 public Table createPanel(Composite parent, String prefs_stack_col_class, 168 String prefs_stack_col_method, String prefs_stack_col_file, String prefs_stack_col_line, 169 String prefs_stack_col_native, IPreferenceStore store) { 170 171 mStackTraceTable = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION); 172 mStackTraceTable.setHeaderVisible(true); 173 mStackTraceTable.setLinesVisible(true); 174 175 TableHelper.createTableColumn( 176 mStackTraceTable, 177 "Class", 178 SWT.LEFT, 179 "SomeLongClassName", //$NON-NLS-1$ 180 prefs_stack_col_class, store); 181 182 TableHelper.createTableColumn( 183 mStackTraceTable, 184 "Method", 185 SWT.LEFT, 186 "someLongMethod", //$NON-NLS-1$ 187 prefs_stack_col_method, store); 188 189 TableHelper.createTableColumn( 190 mStackTraceTable, 191 "File", 192 SWT.LEFT, 193 "android/somepackage/someotherpackage/somefile.class", //$NON-NLS-1$ 194 prefs_stack_col_file, store); 195 196 TableHelper.createTableColumn( 197 mStackTraceTable, 198 "Line", 199 SWT.RIGHT, 200 "99999", //$NON-NLS-1$ 201 prefs_stack_col_line, store); 202 203 TableHelper.createTableColumn( 204 mStackTraceTable, 205 "Native", 206 SWT.LEFT, 207 "Native", //$NON-NLS-1$ 208 prefs_stack_col_native, store); 209 210 mStackTraceViewer = new TableViewer(mStackTraceTable); 211 mStackTraceViewer.setContentProvider(new StackTraceContentProvider()); 212 mStackTraceViewer.setLabelProvider(new StackTraceLabelProvider()); 213 214 mStackTraceViewer.addDoubleClickListener(new IDoubleClickListener() { 215 public void doubleClick(DoubleClickEvent event) { 216 if (sSourceRevealer != null && mCurrentClient != null) { 217 // get the selected stack trace element 218 ISelection selection = mStackTraceViewer.getSelection(); 219 220 if (selection instanceof IStructuredSelection) { 221 IStructuredSelection structuredSelection = (IStructuredSelection)selection; 222 Object object = structuredSelection.getFirstElement(); 223 if (object instanceof StackTraceElement) { 224 StackTraceElement traceElement = (StackTraceElement)object; 225 226 if (traceElement.isNativeMethod() == false) { 227 sSourceRevealer.reveal( 228 mCurrentClient.getClientData().getClientDescription(), 229 traceElement.getClassName(), 230 traceElement.getLineNumber()); 231 } 232 } 233 } 234 } 235 } 236 }); 237 238 return mStackTraceTable; 239 } 240 241 /** 242 * Sets the input for the {@link TableViewer}. 243 * @param input the {@link IStackTraceInfo} that will provide the viewer with the list of 244 * {@link StackTraceElement} 245 */ 246 public void setViewerInput(IStackTraceInfo input) { 247 mStackTraceViewer.setInput(input); 248 mStackTraceViewer.refresh(); 249 } 250 251 /** 252 * Sets the current client running the stack trace. 253 * @param currentClient the {@link Client}. 254 */ 255 public void setCurrentClient(Client currentClient) { 256 mCurrentClient = currentClient; 257 } 258 } 259