• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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