Home | History | Annotate | Download | only in views
      1 /*
      2  * Copyright (C) 2007 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.ide.eclipse.ddms.views;
     18 
     19 import com.android.ddmlib.Log.LogLevel;
     20 import com.android.ddmuilib.logcat.LogColors;
     21 import com.android.ddmuilib.logcat.LogFilter;
     22 import com.android.ddmuilib.logcat.LogPanel;
     23 import com.android.ddmuilib.logcat.LogPanel.ILogFilterStorageManager;
     24 import com.android.ide.eclipse.ddms.CommonAction;
     25 import com.android.ide.eclipse.ddms.DdmsPlugin;
     26 import com.android.ide.eclipse.ddms.ImageLoader;
     27 import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer;
     28 
     29 import org.eclipse.core.resources.IFile;
     30 import org.eclipse.core.resources.IMarker;
     31 import org.eclipse.core.runtime.CoreException;
     32 import org.eclipse.core.runtime.NullProgressMonitor;
     33 import org.eclipse.core.runtime.Status;
     34 import org.eclipse.jdt.core.search.IJavaSearchConstants;
     35 import org.eclipse.jdt.core.search.SearchEngine;
     36 import org.eclipse.jdt.core.search.SearchMatch;
     37 import org.eclipse.jdt.core.search.SearchParticipant;
     38 import org.eclipse.jdt.core.search.SearchPattern;
     39 import org.eclipse.jdt.core.search.SearchRequestor;
     40 import org.eclipse.jface.action.Action;
     41 import org.eclipse.jface.action.IAction;
     42 import org.eclipse.jface.action.IMenuManager;
     43 import org.eclipse.jface.action.IToolBarManager;
     44 import org.eclipse.jface.action.Separator;
     45 import org.eclipse.swt.dnd.Clipboard;
     46 import org.eclipse.swt.graphics.Color;
     47 import org.eclipse.swt.graphics.Font;
     48 import org.eclipse.swt.graphics.FontData;
     49 import org.eclipse.swt.widgets.Composite;
     50 import org.eclipse.swt.widgets.Display;
     51 import org.eclipse.ui.IActionBars;
     52 import org.eclipse.ui.IPerspectiveRegistry;
     53 import org.eclipse.ui.IWorkbenchPage;
     54 import org.eclipse.ui.IWorkbenchWindow;
     55 import org.eclipse.ui.actions.ActionFactory;
     56 import org.eclipse.ui.ide.IDE;
     57 import org.eclipse.ui.internal.WorkbenchPlugin;
     58 import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
     59 
     60 import java.util.ArrayList;
     61 import java.util.HashMap;
     62 import java.util.regex.Matcher;
     63 import java.util.regex.Pattern;
     64 
     65 /**
     66  * The log cat view displays log output from the current device selection.
     67  *
     68  */
     69 public final class LogCatView extends SelectionDependentViewPart {
     70 
     71     public static final String ID =
     72         "com.android.ide.eclipse.ddms.views.LogCatView"; // $NON-NLS-1$
     73 
     74     private static final String PREFS_COL_TIME =
     75         DdmsPlugin.PLUGIN_ID + ".logcat.time"; // $NON-NLS-1$
     76     private static final String PREFS_COL_LEVEL =
     77         DdmsPlugin.PLUGIN_ID + ".logcat.level"; // $NON-NLS-1$
     78     private static final String PREFS_COL_PID =
     79         DdmsPlugin.PLUGIN_ID + ".logcat.pid"; // $NON-NLS-1$
     80     private static final String PREFS_COL_TAG =
     81         DdmsPlugin.PLUGIN_ID + ".logcat.tag"; // $NON-NLS-1$
     82     private static final String PREFS_COL_MESSAGE =
     83         DdmsPlugin.PLUGIN_ID + ".logcat.message"; // $NON-NLS-1$
     84 
     85     private static final String PREFS_FILTERS =
     86         DdmsPlugin.PLUGIN_ID + ".logcat.filters"; // $NON-NLS-1$
     87 
     88     private static LogCatView sThis;
     89     private LogPanel mLogPanel;
     90 
     91     private CommonAction mCreateFilterAction;
     92     private CommonAction mDeleteFilterAction;
     93     private CommonAction mEditFilterAction;
     94     private CommonAction mExportAction;
     95     private CommonAction gotoLineAction;
     96 
     97     private CommonAction[] mLogLevelActions;
     98     private String[] mLogLevelIcons = {
     99             "v.png", //$NON-NLS-1S
    100             "d.png", //$NON-NLS-1S
    101             "i.png", //$NON-NLS-1S
    102             "w.png", //$NON-NLS-1S
    103             "e.png", //$NON-NLS-1S
    104     };
    105 
    106     private Action mClearAction;
    107 
    108     private Clipboard mClipboard;
    109 
    110     /**
    111      * An implementation of {@link ILogFilterStorageManager} to bridge to the eclipse preference
    112      * store, and saves the log filters.
    113      */
    114     private final class FilterStorage implements ILogFilterStorageManager {
    115 
    116         public LogFilter[] getFilterFromStore() {
    117             String filterPrefs = DdmsPlugin.getDefault().getPreferenceStore().getString(
    118                     PREFS_FILTERS);
    119 
    120             // split in a string per filter
    121             String[] filters = filterPrefs.split("\\|"); // $NON-NLS-1$
    122 
    123             ArrayList<LogFilter> list =
    124                 new ArrayList<LogFilter>(filters.length);
    125 
    126             for (String f : filters) {
    127                 if (f.length() > 0) {
    128                     LogFilter logFilter = new LogFilter();
    129                     if (logFilter.loadFromString(f)) {
    130                         list.add(logFilter);
    131                     }
    132                 }
    133             }
    134 
    135             return list.toArray(new LogFilter[list.size()]);
    136         }
    137 
    138         public void saveFilters(LogFilter[] filters) {
    139             StringBuilder sb = new StringBuilder();
    140             for (LogFilter f : filters) {
    141                 String filterString = f.toString();
    142                 sb.append(filterString);
    143                 sb.append('|');
    144             }
    145 
    146             DdmsPlugin.getDefault().getPreferenceStore().setValue(PREFS_FILTERS, sb.toString());
    147         }
    148 
    149         public boolean requiresDefaultFilter() {
    150             return true;
    151         }
    152     }
    153 
    154     public LogCatView() {
    155         sThis = this;
    156         LogPanel.PREFS_TIME = PREFS_COL_TIME;
    157         LogPanel.PREFS_LEVEL = PREFS_COL_LEVEL;
    158         LogPanel.PREFS_PID = PREFS_COL_PID;
    159         LogPanel.PREFS_TAG = PREFS_COL_TAG;
    160         LogPanel.PREFS_MESSAGE = PREFS_COL_MESSAGE;
    161     }
    162 
    163     /**
    164      * Returns the singleton instance.
    165      */
    166     public static LogCatView getInstance() {
    167         return sThis;
    168     }
    169 
    170     /**
    171      * Sets the display font.
    172      * @param font The font.
    173      */
    174     public static void setFont(Font font) {
    175         if (sThis != null && sThis.mLogPanel != null) {
    176             sThis.mLogPanel.setFont(font);
    177         }
    178     }
    179 
    180     @Override
    181     public void createPartControl(Composite parent) {
    182         Display d = parent.getDisplay();
    183         LogColors colors = new LogColors();
    184 
    185         ImageLoader loader = DdmsPlugin.getImageLoader();
    186 
    187         colors.infoColor = new Color(d, 0, 127, 0);
    188         colors.debugColor = new Color(d, 0, 0, 127);
    189         colors.errorColor = new Color(d, 255, 0, 0);
    190         colors.warningColor = new Color(d, 255, 127, 0);
    191         colors.verboseColor = new Color(d, 0, 0, 0);
    192 
    193         mCreateFilterAction = new CommonAction("Create Filter") {
    194             @Override
    195             public void run() {
    196                 mLogPanel.addFilter();
    197             }
    198         };
    199         mCreateFilterAction.setToolTipText("Create Filter");
    200         mCreateFilterAction.setImageDescriptor(loader
    201                 .loadDescriptor("add.png")); // $NON-NLS-1$
    202 
    203         mEditFilterAction = new CommonAction("Edit Filter") {
    204             @Override
    205             public void run() {
    206                 mLogPanel.editFilter();
    207             }
    208         };
    209         mEditFilterAction.setToolTipText("Edit Filter");
    210         mEditFilterAction.setImageDescriptor(loader
    211                 .loadDescriptor("edit.png")); // $NON-NLS-1$
    212 
    213         mDeleteFilterAction = new CommonAction("Delete Filter") {
    214             @Override
    215             public void run() {
    216                 mLogPanel.deleteFilter();
    217             }
    218         };
    219         mDeleteFilterAction.setToolTipText("Delete Filter");
    220         mDeleteFilterAction.setImageDescriptor(loader
    221                 .loadDescriptor("delete.png")); // $NON-NLS-1$
    222 
    223         mExportAction = new CommonAction("Export Selection As Text...") {
    224             @Override
    225             public void run() {
    226                 mLogPanel.save();
    227             }
    228         };
    229         mExportAction.setToolTipText("Export Selection As Text...");
    230         mExportAction.setImageDescriptor(loader.loadDescriptor("save.png")); // $NON-NLS-1$
    231 
    232         gotoLineAction = new CommonAction("Go to Problem") {
    233             @Override
    234             public void run() {
    235                 goToErrorLine();
    236             }
    237         };
    238 
    239         LogLevel[] levels = LogLevel.values();
    240         mLogLevelActions = new CommonAction[mLogLevelIcons.length];
    241         for (int i = 0 ; i < mLogLevelActions.length; i++) {
    242             String name = levels[i].getStringValue();
    243             mLogLevelActions[i] = new CommonAction(name, IAction.AS_CHECK_BOX) {
    244                 @Override
    245                 public void run() {
    246                     // disable the other actions and record current index
    247                     for (int i = 0 ; i < mLogLevelActions.length; i++) {
    248                         Action a = mLogLevelActions[i];
    249                         if (a == this) {
    250                             a.setChecked(true);
    251 
    252                             // set the log level
    253                             mLogPanel.setCurrentFilterLogLevel(i+2);
    254                         } else {
    255                             a.setChecked(false);
    256                         }
    257                     }
    258                 }
    259             };
    260 
    261             mLogLevelActions[i].setToolTipText(name);
    262             mLogLevelActions[i].setImageDescriptor(loader.loadDescriptor(mLogLevelIcons[i]));
    263         }
    264 
    265         mClearAction = new Action("Clear Log") {
    266             @Override
    267             public void run() {
    268                 mLogPanel.clear();
    269             }
    270         };
    271         mClearAction.setImageDescriptor(loader
    272                 .loadDescriptor("clear.png")); // $NON-NLS-1$
    273 
    274 
    275         // now create the log view
    276         mLogPanel = new LogPanel(loader, colors, new FilterStorage(), LogPanel.FILTER_MANUAL);
    277         mLogPanel.setActions(mDeleteFilterAction, mEditFilterAction, mLogLevelActions);
    278 
    279         // get the font
    280         String fontStr = DdmsPlugin.getDefault().getPreferenceStore().getString(
    281                 PreferenceInitializer.ATTR_LOGCAT_FONT);
    282         if (fontStr != null) {
    283             FontData data = new FontData(fontStr);
    284 
    285             if (fontStr != null) {
    286                 mLogPanel.setFont(new Font(parent.getDisplay(), data));
    287             }
    288         }
    289 
    290         mLogPanel.createPanel(parent);
    291         setSelectionDependentPanel(mLogPanel);
    292 
    293         // place the actions.
    294         placeActions();
    295 
    296         // setup the copy action
    297         mClipboard = new Clipboard(d);
    298         IActionBars actionBars = getViewSite().getActionBars();
    299         actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), new Action("Copy") {
    300             @Override
    301             public void run() {
    302                 mLogPanel.copy(mClipboard);
    303             }
    304         });
    305 
    306         // setup the select all action
    307         actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(),
    308                 new Action("Select All") {
    309             @Override
    310             public void run() {
    311                 mLogPanel.selectAll();
    312             }
    313         });
    314     }
    315 
    316     @Override
    317     public void dispose() {
    318         mLogPanel.stopLogCat(true);
    319         mClipboard.dispose();
    320     }
    321 
    322     @Override
    323     public void setFocus() {
    324         mLogPanel.setFocus();
    325     }
    326 
    327     /**
    328      * Place the actions in the ui.
    329      */
    330     private void placeActions() {
    331         IActionBars actionBars = getViewSite().getActionBars();
    332 
    333         // first in the menu
    334         IMenuManager menuManager = actionBars.getMenuManager();
    335         menuManager.add(mCreateFilterAction);
    336         menuManager.add(mEditFilterAction);
    337         menuManager.add(mDeleteFilterAction);
    338         menuManager.add(new Separator());
    339         menuManager.add(mClearAction);
    340         menuManager.add(new Separator());
    341         menuManager.add(mExportAction);
    342         menuManager.add(gotoLineAction);
    343 
    344         // and then in the toolbar
    345         IToolBarManager toolBarManager = actionBars.getToolBarManager();
    346         for (CommonAction a : mLogLevelActions) {
    347             toolBarManager.add(a);
    348         }
    349         toolBarManager.add(new Separator());
    350         toolBarManager.add(mCreateFilterAction);
    351         toolBarManager.add(mEditFilterAction);
    352         toolBarManager.add(mDeleteFilterAction);
    353         toolBarManager.add(new Separator());
    354         toolBarManager.add(mClearAction);
    355     }
    356 
    357     IMarker createMarkerFromSearchMatch(IFile file, SearchMatch match) {
    358         HashMap<String, Object> map = new HashMap<String, Object>();
    359         map.put(IMarker.CHAR_START, new Integer(match.getOffset()));
    360         map.put(IMarker.CHAR_END, new Integer(match.getOffset()
    361                 + match.getLength()));
    362         IMarker marker = null;
    363         try {
    364             marker = file.createMarker(IMarker.TEXT);
    365             marker.setAttributes(map);
    366         } catch (CoreException e) {
    367             Status s = new Status(Status.ERROR, DdmsPlugin.PLUGIN_ID, e.getMessage(), e);
    368             DdmsPlugin.getDefault().getLog().log(s);
    369         }
    370         return marker;
    371     }
    372 
    373     void openFile(IFile file, IMarker marker) {
    374         try {
    375             IWorkbenchPage page = getViewSite().getWorkbenchWindow()
    376                     .getActivePage();
    377             if (page != null) {
    378                 IDE.openEditor(page, marker);
    379                 marker.delete();
    380             }
    381         } catch (CoreException e) {
    382             Status s = new Status(Status.ERROR, DdmsPlugin.PLUGIN_ID, e.getMessage(), e);
    383             DdmsPlugin.getDefault().getLog().log(s);
    384         }
    385     }
    386 
    387     void switchPerspective() {
    388 
    389         IWorkbenchWindow window = getViewSite().getWorkbenchWindow()
    390                 .getWorkbench().getActiveWorkbenchWindow();
    391         String rtPerspectiveId = "org.eclipse.jdt.ui.JavaPerspective";
    392         IPerspectiveRegistry reg = WorkbenchPlugin.getDefault()
    393                 .getPerspectiveRegistry();
    394         PerspectiveDescriptor rtPerspectiveDesc = (PerspectiveDescriptor) reg
    395                 .findPerspectiveWithId(rtPerspectiveId);
    396         if (window != null) {
    397             IWorkbenchPage page = window.getActivePage();
    398             page.setPerspective(rtPerspectiveDesc);
    399         }
    400     }
    401 
    402     void goToErrorLine() {
    403         try {
    404             String msg = mLogPanel.getSelectedErrorLineMessage();
    405             if (msg != null) {
    406                 String error_line_matcher_string = "\\s*at\\ (.*)\\((.*\\.java)\\:(\\d+)\\)";
    407                 Matcher error_line_matcher = Pattern.compile(
    408                         error_line_matcher_string).matcher(msg);
    409 
    410                 if (error_line_matcher.find()) {
    411                     String class_name = error_line_matcher.group(1);
    412 
    413                     // TODO: Search currently only matches the class declaration (using
    414                     // IJavaSearchConstants.DECLARATIONS). We may want to jump to the
    415                     // "reference" of the class instead (IJavaSearchConstants.REFERENCES)
    416                     // using the filename and line number to disambiguate the search results.
    417 //                  String filename = error_line_matcher.group(2);
    418 //                  int line_number = Integer.parseInt(error_line_matcher.group(3));
    419 
    420                     SearchEngine se = new SearchEngine();
    421                     se.search(SearchPattern.createPattern(class_name,
    422                             IJavaSearchConstants.METHOD,
    423                             IJavaSearchConstants.DECLARATIONS,
    424                             SearchPattern.R_EXACT_MATCH
    425                                     | SearchPattern.R_CASE_SENSITIVE),
    426                             new SearchParticipant[] { SearchEngine
    427                                     .getDefaultSearchParticipant() },
    428                             SearchEngine.createWorkspaceScope(),
    429                             new SearchRequestor() {
    430                                 boolean found_first_match = false;
    431 
    432                                 @Override
    433                                 public void acceptSearchMatch(
    434                                         SearchMatch match)
    435                                         throws CoreException {
    436 
    437                                     if (match.getResource() instanceof IFile
    438                                             && !found_first_match) {
    439                                         found_first_match = true;
    440 
    441                                         IFile matched_file = (IFile) match
    442                                                 .getResource();
    443                                         IMarker marker = createMarkerFromSearchMatch(
    444                                                 matched_file, match);
    445 
    446                                         // There should only be one exact match,
    447                                         // so we go immediately to that one.
    448                                         switchPerspective();
    449                                         openFile(matched_file, marker);
    450                                     }
    451                                 }
    452                             }, new NullProgressMonitor());
    453 
    454                 }
    455             }
    456         } catch (Exception e) {
    457             Status s = new Status(Status.ERROR, DdmsPlugin.PLUGIN_ID, e.getMessage(), e);
    458             DdmsPlugin.getDefault().getLog().log(s);
    459         }
    460     }
    461  }
    462 
    463