Home | History | Annotate | Download | only in views
      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
     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
    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 
    129         public LogCatViewSearchRequestor(String choice, int lineNumber) {
    130             super();
    131             mChoice = choice;
    132             mLineNumber = lineNumber;
    133         }
    134 
    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
    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      */
    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 
    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 
    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 
    251     public void selectTransientAppFilter(String appName) {
    252         mLogCatPanel.selectTransientAppFilter(appName);
    253     }
    254 }
    255