• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 package com.android.ide.eclipse.ddms.views;
17 
18 import com.android.ddmlib.IDevice;
19 import com.android.ddmuilib.logcat.ILogCatMessageSelectionListener;
20 import com.android.ddmuilib.logcat.LogCatMessage;
21 import com.android.ddmuilib.logcat.LogCatPanel;
22 import com.android.ddmuilib.logcat.LogCatStackTraceParser;
23 import com.android.ide.eclipse.ddms.DdmsPlugin;
24 import com.android.ide.eclipse.ddms.i18n.Messages;
25 import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer;
26 
27 import org.eclipse.core.resources.IFile;
28 import org.eclipse.core.resources.IMarker;
29 import org.eclipse.core.runtime.CoreException;
30 import org.eclipse.core.runtime.NullProgressMonitor;
31 import org.eclipse.core.runtime.Status;
32 import org.eclipse.jdt.core.search.IJavaSearchConstants;
33 import org.eclipse.jdt.core.search.SearchEngine;
34 import org.eclipse.jdt.core.search.SearchMatch;
35 import org.eclipse.jdt.core.search.SearchParticipant;
36 import org.eclipse.jdt.core.search.SearchPattern;
37 import org.eclipse.jdt.core.search.SearchRequestor;
38 import org.eclipse.jface.action.Action;
39 import org.eclipse.jface.preference.IPreferenceStore;
40 import org.eclipse.swt.dnd.Clipboard;
41 import org.eclipse.swt.layout.FillLayout;
42 import org.eclipse.swt.widgets.Composite;
43 import org.eclipse.ui.IActionBars;
44 import org.eclipse.ui.IPerspectiveRegistry;
45 import org.eclipse.ui.IWorkbench;
46 import org.eclipse.ui.IWorkbenchPage;
47 import org.eclipse.ui.IWorkbenchWindow;
48 import org.eclipse.ui.PlatformUI;
49 import org.eclipse.ui.WorkbenchException;
50 import org.eclipse.ui.actions.ActionFactory;
51 import org.eclipse.ui.ide.IDE;
52 
53 import java.util.HashMap;
54 import java.util.Map;
55 
56 public class LogCatView extends SelectionDependentViewPart {
57     /** LogCatView ID as defined in plugin.xml. */
58     public static final String ID = "com.android.ide.eclipse.ddms.views.LogCatView"; //$NON-NLS-1$
59 
60     /** Constant indicating that double clicking on a stack trace should
61      * open the method declaration. */
62     public static final String CHOICE_METHOD_DECLARATION =
63             DdmsPlugin.PLUGIN_ID + ".logcat.MethodDeclaration"; //$NON-NLS-1$
64 
65     /** Constant indicating that double clicking on a stack trace should
66      * open the line at which error occurred. */
67     public static final String CHOICE_ERROR_LINE =
68             DdmsPlugin.PLUGIN_ID + ".logcat.ErrorLine"; //$NON-NLS-1$
69 
70     /** Switch perspective when a Java file is opened from logcat view. */
71     public static final boolean DEFAULT_SWITCH_PERSPECTIVE = true;
72 
73     /** Target perspective to open when a Java file is opened from logcat view. */
74     public static final String DEFAULT_PERSPECTIVE_ID =
75             "org.eclipse.jdt.ui.JavaPerspective"; //$NON-NLS-1$
76 
77     private LogCatPanel mLogCatPanel;
78     private LogCatStackTraceParser mStackTraceParser = new LogCatStackTraceParser();
79 
80     private Clipboard mClipboard;
81 
82     @Override
createPartControl(Composite parent)83     public void createPartControl(Composite parent) {
84         parent.setLayout(new FillLayout());
85 
86         IPreferenceStore prefStore = DdmsPlugin.getDefault().getPreferenceStore();
87         mLogCatPanel = new LogCatPanel(prefStore);
88         mLogCatPanel.createPanel(parent);
89         setSelectionDependentPanel(mLogCatPanel);
90 
91         mLogCatPanel.addLogCatMessageSelectionListener(new ILogCatMessageSelectionListener() {
92             public void messageDoubleClicked(LogCatMessage m) {
93                 onDoubleClick(m);
94             }
95         });
96 
97         mClipboard = new Clipboard(parent.getDisplay());
98         IActionBars actionBars = getViewSite().getActionBars();
99         actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(),
100                 new Action(Messages.LogCatView_Copy) {
101             @Override
102             public void run() {
103                 mLogCatPanel.copySelectionToClipboard(mClipboard);
104             }
105         });
106 
107         actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(),
108                 new Action(Messages.LogCatView_Select_All) {
109             @Override
110             public void run() {
111                 mLogCatPanel.selectAll();
112             }
113         });
114     }
115 
116     @Override
setFocus()117     public void setFocus() {
118     }
119 
120     /**
121      * This class defines what to do with the search match returned by a
122      * double-click or by the Go to Problem action.
123      */
124     private class LogCatViewSearchRequestor extends SearchRequestor {
125         private boolean mFoundFirstMatch = false;
126         private String mChoice;
127         private int mLineNumber;
128 
LogCatViewSearchRequestor(String choice, int lineNumber)129         public LogCatViewSearchRequestor(String choice, int lineNumber) {
130             super();
131             mChoice = choice;
132             mLineNumber = lineNumber;
133         }
134 
createMarkerFromSearchMatch(IFile file, SearchMatch match)135         IMarker createMarkerFromSearchMatch(IFile file, SearchMatch match) {
136             IMarker marker = null;
137             try {
138                 if (CHOICE_METHOD_DECLARATION.equals(mChoice)) {
139                     Map<String, Object> attrs = new HashMap<String, Object>();
140                     attrs.put(IMarker.CHAR_START, Integer.valueOf(match.getOffset()));
141                     attrs.put(IMarker.CHAR_END, Integer.valueOf(match.getOffset()
142                             + match.getLength()));
143                     marker = file.createMarker(IMarker.TEXT);
144                     marker.setAttributes(attrs);
145                 } else if (CHOICE_ERROR_LINE.equals(mChoice)) {
146                     marker = file.createMarker(IMarker.TEXT);
147                     marker.setAttribute(IMarker.LINE_NUMBER, mLineNumber);
148                 }
149             } catch (CoreException e) {
150                 Status s = new Status(Status.ERROR, DdmsPlugin.PLUGIN_ID, e.getMessage(), e);
151                 DdmsPlugin.getDefault().getLog().log(s);
152             }
153             return marker;
154         }
155 
156         @Override
acceptSearchMatch(SearchMatch match)157         public void acceptSearchMatch(SearchMatch match) throws CoreException {
158             if (match.getResource() instanceof IFile && !mFoundFirstMatch) {
159                 mFoundFirstMatch = true;
160                 IFile matchedFile = (IFile) match.getResource();
161                 IMarker marker = createMarkerFromSearchMatch(matchedFile, match);
162                 // There should only be one exact match,
163                 // so we go immediately to that one.
164                 if (marker != null) {
165                     switchPerspective();
166                     showMarker(marker);
167                 }
168             }
169         }
170     }
171 
172     /**
173      * Switch to perspective specified by user when opening a source file.
174      * User preferences control whether the perspective should be switched,
175      * and if so, what the target perspective is.
176      */
switchPerspective()177     private void switchPerspective() {
178         IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore();
179         if (store.getBoolean(PreferenceInitializer.ATTR_SWITCH_PERSPECTIVE)) {
180             IWorkbench workbench = PlatformUI.getWorkbench();
181             IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
182             IPerspectiveRegistry perspectiveRegistry = workbench.getPerspectiveRegistry();
183             String perspectiveId = store.getString(PreferenceInitializer.ATTR_PERSPECTIVE_ID);
184             if (perspectiveId != null
185                     && perspectiveId.length() > 0
186                     && perspectiveRegistry.findPerspectiveWithId(perspectiveId) != null) {
187                 try {
188                     workbench.showPerspective(perspectiveId, window);
189                 } catch (WorkbenchException e) {
190                     Status s = new Status(Status.ERROR, DdmsPlugin.PLUGIN_ID, e.getMessage(), e);
191                     DdmsPlugin.getDefault().getLog().log(s);
192                 }
193             }
194         }
195     }
196 
showMarker(IMarker marker)197     private void showMarker(IMarker marker) {
198         try {
199             IWorkbenchPage page = getViewSite().getWorkbenchWindow()
200                     .getActivePage();
201             if (page != null) {
202                 IDE.openEditor(page, marker);
203                 marker.delete();
204             }
205         } catch (CoreException e) {
206             Status s = new Status(Status.ERROR, DdmsPlugin.PLUGIN_ID, e.getMessage(), e);
207             DdmsPlugin.getDefault().getLog().log(s);
208         }
209     }
210 
onDoubleClick(LogCatMessage m)211     private void onDoubleClick(LogCatMessage m) {
212         String msg = m.getMessage();
213         if (!mStackTraceParser.isValidExceptionTrace(msg)) {
214             return;
215         }
216 
217         String methodName = mStackTraceParser.getMethodName(msg);
218         String fileName = mStackTraceParser.getFileName(msg);
219         int lineNumber = mStackTraceParser.getLineNumber(msg);
220 
221         IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore();
222         String jumpToLocation = store.getString(PreferenceInitializer.ATTR_LOGCAT_GOTO_PROBLEM);
223 
224         String stringPattern = methodName;
225         LogCatViewSearchRequestor requestor =
226                 new LogCatViewSearchRequestor(CHOICE_METHOD_DECLARATION, 0);
227         int searchFor = IJavaSearchConstants.METHOD;
228         if (jumpToLocation.equals(CHOICE_ERROR_LINE)) {
229             searchFor = IJavaSearchConstants.CLASS;
230             stringPattern = fileName;
231             requestor = new LogCatViewSearchRequestor(CHOICE_ERROR_LINE, lineNumber);
232         }
233 
234         SearchEngine se = new SearchEngine();
235         SearchPattern searchPattern = SearchPattern.createPattern(stringPattern,
236                 searchFor,
237                 IJavaSearchConstants.DECLARATIONS,
238                 SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
239         try {
240             se.search(searchPattern,
241                     new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
242                     SearchEngine.createWorkspaceScope(),
243                     requestor,
244                     new NullProgressMonitor());
245         } catch (CoreException e) {
246             Status s = new Status(Status.ERROR, DdmsPlugin.PLUGIN_ID, e.getMessage(), e);
247             DdmsPlugin.getDefault().getLog().log(s);
248         }
249     }
250 
selectTransientAppFilter(String appName)251     public void selectTransientAppFilter(String appName) {
252         mLogCatPanel.selectTransientAppFilter(appName);
253     }
254 }
255