diff options
6 files changed, 817 insertions, 6 deletions
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java new file mode 100644 index 0000000..c55a308 --- /dev/null +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ddmuilib.logcat; + +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.Viewer; + +import java.util.List; + +/** + * A JFace content provider for logcat filter list, used in {@link LogCatPanel}. + */ +public final class LogCatFilterContentProvider implements IStructuredContentProvider { + public void dispose() { + } + + public void inputChanged(Viewer arg0, Object arg1, Object arg2) { + } + + /** + * Obtain the list of filters currently in use. + * @param model list of {@link LogCatFilterSettings}'s + * @return array of {@link LogCatFilterSettings} objects, or null. + */ + public Object[] getElements(Object model) { + if (model instanceof List<?>) { + return ((List<?>) model).toArray(); + } + return null; + } + +} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java new file mode 100644 index 0000000..c5a1e68 --- /dev/null +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ddmuilib.logcat; + +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.graphics.Image; + +/** + * A JFace label provider for the LogCat filters. It expects elements of type + * {@link LogCatFilterSettings}. + */ +public final class LogCatFilterLabelProvider extends LabelProvider implements ITableLabelProvider { + public Image getColumnImage(Object arg0, int arg1) { + return null; + } + + /** + * Implements {@link ITableLabelProvider#getColumnText(Object, int)}. + * @param element an instance of {@link LogCatFilterSettings} + * @param index index of the column + * @return text to use in the column + */ + public String getColumnText(Object element, int index) { + if (!(element instanceof LogCatFilterSettings)) { + return null; + } + + LogCatFilterSettings f = (LogCatFilterSettings) element; + + /* FIXME: Currently, only the name of the filter is displayed. + * A future fix will also display the "unread count" associated + * with each filter. */ + switch (index) { + case 0: + return f.getName(); + default: + return "**"; + } + } +} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettings.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettings.java new file mode 100644 index 0000000..7dba6d8 --- /dev/null +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettings.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ddmuilib.logcat; + +import com.android.ddmlib.Log.LogLevel; + +/** + * Settings for a filter for logcat messages. + */ +public final class LogCatFilterSettings { + private final String mName; + private final String mTag; + private final String mPid; + private final LogLevel mLogLevel; + + public LogCatFilterSettings(String name, String tag, String pid, LogLevel logLevel) { + mName = name; + mTag = tag; + mPid = pid; + mLogLevel = logLevel; + } + + public String getName() { + return mName; + } + + public String getTag() { + return mTag; + } + + public String getPidString() { + return mPid; + } + + public LogLevel getLogLevel() { + return mLogLevel; + } +} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java new file mode 100644 index 0000000..52c0c0a --- /dev/null +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ddmuilib.logcat; + +import com.android.ddmlib.Log.LogLevel; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Dialog used to create or edit settings for a logcat filter. + */ +public final class LogCatFilterSettingsDialog extends TitleAreaDialog { + private static final String TITLE = "Logcat Message Filter Settings"; + private static final String DEFAULT_MESSAGE = + "Filter logcat messages by the source's tag, pid or minimum log level.\n" + + "Empty fields will match all messages."; + + private String mFilterName; + private String mTag; + private String mPID; + private String mLogLevel; + + private Text mFilterNameText; + private Text mTagFilterText; + private Text mPIDFilterText; + private Combo mLogLevelCombo; + private Button mOkButton; + + /** + * Construct the filter settings dialog with default values for all fields. + * @param parentShell . + */ + public LogCatFilterSettingsDialog(Shell parentShell) { + super(parentShell); + setDefaults("", "", "", LogLevel.VERBOSE); + } + + /** + * Set the default values to show when the dialog is opened. + * @param filterName name for the filter. + * @param tag value for filter by tag + * @param pid value for filter by pid + * @param level value for filter by log level + */ + public void setDefaults(String filterName, String tag, String pid, LogLevel level) { + mFilterName = filterName; + mTag = tag; + mPID = pid; + mLogLevel = level.getStringValue(); + } + + @Override + protected Control createDialogArea(Composite shell) { + setTitle(TITLE); + setMessage(DEFAULT_MESSAGE); + + Composite parent = (Composite) super.createDialogArea(shell); + Composite c = new Composite(parent, SWT.BORDER); + c.setLayout(new GridLayout(2, false)); + c.setLayoutData(new GridData(GridData.FILL_BOTH)); + + createLabel(c, "Filter Name:"); + mFilterNameText = new Text(c, SWT.BORDER); + mFilterNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mFilterNameText.setText(mFilterName); + + createSeparator(c); + + createLabel(c, "by Log Tag:"); + mTagFilterText = new Text(c, SWT.BORDER); + mTagFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mTagFilterText.setText(mTag); + + createLabel(c, "by PID:"); + mPIDFilterText = new Text(c, SWT.BORDER); + mPIDFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mPIDFilterText.setText(mPID); + + createLabel(c, "by Log Level:"); + mLogLevelCombo = new Combo(c, SWT.READ_ONLY | SWT.DROP_DOWN); + mLogLevelCombo.setItems(getLogLevels().toArray(new String[0])); + mLogLevelCombo.select(getLogLevels().indexOf(mLogLevel)); + + /* call validateDialog() whenever user modifies any text field */ + ModifyListener m = new ModifyListener() { + public void modifyText(ModifyEvent arg0) { + DialogStatus status = validateDialog(); + mOkButton.setEnabled(status.valid); + setErrorMessage(status.message); + } + }; + mFilterNameText.addModifyListener(m); + mTagFilterText.addModifyListener(m); + mPIDFilterText.addModifyListener(m); + + return c; + } + + + @Override + protected void createButtonsForButtonBar(Composite parent) { + super.createButtonsForButtonBar(parent); + + mOkButton = getButton(IDialogConstants.OK_ID); + + DialogStatus status = validateDialog(); + mOkButton.setEnabled(status.valid); + } + + /** + * A tuple that specifies whether the current state of the inputs + * on the dialog is valid or not. If it is not valid, the message + * field stores the reason why it isn't. + */ + private final class DialogStatus { + final boolean valid; + final String message; + + private DialogStatus(boolean isValid, String errMessage) { + valid = isValid; + message = errMessage; + } + } + + private DialogStatus validateDialog() { + /* check that there is some name for the filter */ + if (mFilterNameText.getText().trim().equals("")) { + return new DialogStatus(false, + "Please provide a name for this filter."); + } + + /* if a pid is provided, it should be a +ve integer */ + String pidText = mPIDFilterText.getText().trim(); + if (!pidText.equals("")) { + int pid = 0; + try { + pid = Integer.parseInt(pidText); + } catch (NumberFormatException e) { + return new DialogStatus(false, + "PID should be a positive integer."); + } + + if (pid < 0) { + return new DialogStatus(false, + "PID should be a positive integer."); + } + } + + /* tag field must use a valid regex pattern */ + String tagText = mTagFilterText.getText().trim(); + if (!tagText.equals("")) { + try { + Pattern.compile(tagText); + } catch (PatternSyntaxException e) { + return new DialogStatus(false, + "Invalid regex used in tag field: " + e.getMessage()); + } + } + + return new DialogStatus(true, null); + } + + private void createSeparator(Composite c) { + Label l = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + l.setLayoutData(gd); + } + + private void createLabel(Composite c, String text) { + Label l = new Label(c, SWT.NONE); + l.setText(text); + GridData gd = new GridData(); + gd.horizontalAlignment = SWT.RIGHT; + l.setLayoutData(gd); + } + + @Override + protected void okPressed() { + /* save values from the widgets before the shell is closed. */ + mFilterName = mFilterNameText.getText(); + mTag = mTagFilterText.getText(); + mLogLevel = mLogLevelCombo.getText(); + + String pidText = mPIDFilterText.getText().trim(); + if (!pidText.equals("")) { + mPID = pidText; + } + + super.okPressed(); + } + + /** + * Obtain the name for this filter. + * @return user provided filter name, maybe empty. + */ + public String getFilterName() { + return mFilterName; + } + + /** + * Obtain the tag regex to filter by. + * @return user provided tag regex, maybe empty. + */ + public String getTag() { + return mTag; + } + + /** + * Obtain user provided PID to filter by. + * @return user provided pid, maybe empty. + */ + public String getPID() { + return mPID; + } + + /** + * Obtain log level to filter by. + * @return log level string. + */ + public String getLogLevel() { + return mLogLevel; + } + + /** + * Obtain the string representation of all supported log levels. + * @return an array of strings, each representing a certain log level. + */ + public static List<String> getLogLevels() { + List<String> logLevels = new ArrayList<String>(); + + for (LogLevel l : LogLevel.values()) { + logLevels.add(l.getStringValue()); + } + + return logLevels; + } +} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java index 8fdf357..d4e1926 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java @@ -16,18 +16,33 @@ package com.android.ddmuilib.logcat; +import com.android.ddmlib.Log.LogLevel; +import com.android.ddmuilib.ImageLoader; import com.android.ddmuilib.SelectionDependentPanel; import com.android.ddmuilib.TableHelper; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +import java.util.ArrayList; +import java.util.List; /** * LogCatPanel displays a table listing the logcat messages. @@ -39,10 +54,35 @@ public final class LogCatPanel extends SelectionDependentPanel * FIXME: this should be a preference. */ private static final int MSG_WRAP_WIDTH = 150; - private TableViewer mViewer; + /** Default message to show in the message search field. */ + private static final String DEFAULT_SEARCH_MESSAGE = + "Search for messages. Accepts Java regexes. " + + "Prefix with pid:, tag: or text: to limit scope."; + + private static final String IMAGE_ADD_FILTER = "add.png"; //$NON-NLS-1$ + private static final String IMAGE_DELETE_FILTER = "delete.png"; //$NON-NLS-1$ + private static final String IMAGE_EDIT_FILTER = "edit.png"; //$NON-NLS-1$ + private static final String IMAGE_SAVE_LOG_TO_FILE = "save.png"; //$NON-NLS-1$ + private static final String IMAGE_CLEAR_LOG = "clear.png"; //$NON-NLS-1$ + + /* FIXME: create appropriate icon */ + private static final String IMAGE_SCROLL_LOG_TO_LATEST = "halt.png"; //$NON-NLS-1$ + private LogCatReceiver mReceiver; private IPreferenceStore mPrefStore; + private List<LogCatFilterSettings> mLogCatFilters; + + private ToolItem mNewFilterToolItem; + private ToolItem mDeleteFilterToolItem; + private ToolItem mEditFilterToolItem; + private TableViewer mFiltersTableViewer; + + private Combo mLiveFilterLevelCombo; + private Text mLiveFilterText; + + private TableViewer mViewer; + /** * Construct a logcat panel. * @param r source of logcat messages. @@ -51,7 +91,22 @@ public final class LogCatPanel extends SelectionDependentPanel public LogCatPanel(LogCatReceiver r, IPreferenceStore prefStore) { mReceiver = r; mPrefStore = prefStore; + mReceiver.addMessageReceivedEventListener(this); + + initializeFilters(prefStore); + } + + private void initializeFilters(IPreferenceStore prefStore) { + mLogCatFilters = new ArrayList<LogCatFilterSettings>(); + + /* add a couple of filters by default */ + mLogCatFilters.add(new LogCatFilterSettings("All messages (no filters)", + "", "", LogLevel.VERBOSE)); + mLogCatFilters.add(new LogCatFilterSettings("Errors only", + "", "", LogLevel.ERROR)); + + /* FIXME restore saved filters from prefStore */ } @Override @@ -71,23 +126,233 @@ public final class LogCatPanel extends SelectionDependentPanel @Override protected Control createControl(Composite parent) { - GridLayout layout = new GridLayout(2, false); + GridLayout layout = new GridLayout(1, false); parent.setLayout(layout); - createLogcatViewTable(parent); + createViews(parent); + setupDefaults(); return null; } + private void createViews(Composite parent) { + SashForm sash = createSash(parent); + + createListOfFilters(sash); + createLogTableView(sash); + + /* allocate widths of the two columns 20%:80% */ + /* FIXME: save/restore sash widths */ + sash.setWeights(new int[] {20, 80}); + } + + private SashForm createSash(Composite parent) { + SashForm sash = new SashForm(parent, SWT.HORIZONTAL); + sash.setLayoutData(new GridData(GridData.FILL_BOTH)); + return sash; + } + + private void createListOfFilters(SashForm sash) { + Composite c = new Composite(sash, SWT.BORDER); + GridLayout layout = new GridLayout(2, false); + c.setLayout(layout); + c.setLayoutData(new GridData(GridData.FILL_BOTH)); + + createFiltersToolbar(c); + createFiltersTable(c); + } + + private void createFiltersToolbar(Composite parent) { + Label l = new Label(parent, SWT.NONE); + l.setText("Saved Filters"); + GridData gd = new GridData(); + gd.horizontalAlignment = SWT.LEFT; + l.setLayoutData(gd); + + ToolBar t = new ToolBar(parent, SWT.FLAT | SWT.BORDER); + gd = new GridData(); + gd.horizontalAlignment = SWT.RIGHT; + t.setLayoutData(gd); + + /* new filter */ + mNewFilterToolItem = new ToolItem(t, SWT.PUSH); + mNewFilterToolItem.setImage( + ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_ADD_FILTER, t.getDisplay())); + mNewFilterToolItem.setToolTipText("Add a new logcat filter"); + mNewFilterToolItem.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + addNewFilter(); + } + }); + + /* delete filter */ + mDeleteFilterToolItem = new ToolItem(t, SWT.PUSH); + mDeleteFilterToolItem.setImage( + ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_DELETE_FILTER, t.getDisplay())); + mDeleteFilterToolItem.setToolTipText("Delete selected logcat filter"); + mDeleteFilterToolItem.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + deleteSelectedFilter(); + } + }); + + /* edit filter */ + mEditFilterToolItem = new ToolItem(t, SWT.PUSH); + mEditFilterToolItem.setImage( + ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_EDIT_FILTER, t.getDisplay())); + mEditFilterToolItem.setToolTipText("Edit selected logcat filter"); + mEditFilterToolItem.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + editSelectedFilter(); + } + }); + } + + private void addNewFilter() { + LogCatFilterSettingsDialog d = new LogCatFilterSettingsDialog( + Display.getCurrent().getActiveShell()); + if (d.open() != Window.OK) { + return; + } + + LogCatFilterSettings f = new LogCatFilterSettings(d.getFilterName().trim(), + d.getTag().trim(), + d.getPID().trim(), + LogLevel.getByString(d.getLogLevel())); + + mLogCatFilters.add(f); + mFiltersTableViewer.refresh(); + + /* select the newly added entry */ + int idx = mLogCatFilters.size() - 1; + mFiltersTableViewer.getTable().setSelection(idx); + + filterSelectionChanged(); + } + + private void deleteSelectedFilter() { + int selectedIndex = mFiltersTableViewer.getTable().getSelectionIndex(); + if (selectedIndex <= 0) { + /* return if no selected filter, or the default filter was selected (0th). */ + return; + } + + mLogCatFilters.remove(selectedIndex); + mFiltersTableViewer.refresh(); + mFiltersTableViewer.getTable().setSelection(selectedIndex - 1); + + filterSelectionChanged(); + } + + private void editSelectedFilter() { + int selectedIndex = mFiltersTableViewer.getTable().getSelectionIndex(); + if (selectedIndex < 0) { + return; + } + + LogCatFilterSettings curFilter = mLogCatFilters.get(selectedIndex); + + LogCatFilterSettingsDialog dialog = new LogCatFilterSettingsDialog( + Display.getCurrent().getActiveShell()); + dialog.setDefaults(curFilter.getName(), curFilter.getTag(), curFilter.getPidString(), + curFilter.getLogLevel()); + if (dialog.open() != Window.OK) { + return; + } + + LogCatFilterSettings f = new LogCatFilterSettings(dialog.getFilterName(), + dialog.getTag(), + dialog.getPID(), + LogLevel.getByString(dialog.getLogLevel())); + mLogCatFilters.set(selectedIndex, f); + mFiltersTableViewer.refresh(); + + mFiltersTableViewer.getTable().setSelection(selectedIndex); + filterSelectionChanged(); + } + + private void createFiltersTable(Composite parent) { + final Table table = new Table(parent, SWT.FULL_SELECTION); + + GridData gd = new GridData(GridData.FILL_BOTH); + gd.horizontalSpan = 2; + table.setLayoutData(gd); + + mFiltersTableViewer = new TableViewer(table); + mFiltersTableViewer.setContentProvider(new LogCatFilterContentProvider()); + mFiltersTableViewer.setLabelProvider(new LogCatFilterLabelProvider()); + mFiltersTableViewer.setInput(mLogCatFilters); + + mFiltersTableViewer.getTable().addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + filterSelectionChanged(); + } + }); + } + + private void createLogTableView(SashForm sash) { + Composite c = new Composite(sash, SWT.NONE); + c.setLayout(new GridLayout()); + c.setLayoutData(new GridData(GridData.FILL_BOTH)); + + createLiveFilters(c); + createLogcatViewTable(c); + } + + /** + * Create the search bar at the top of the logcat messages table. + * FIXME: Currently, this feature is incomplete: The UI elements are created, but they + * are all set to disabled state. + */ + private void createLiveFilters(Composite parent) { + Composite c = new Composite(parent, SWT.NONE); + c.setLayout(new GridLayout(3, false)); + c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + mLiveFilterText = new Text(c, SWT.BORDER | SWT.SEARCH); + mLiveFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mLiveFilterText.setMessage(DEFAULT_SEARCH_MESSAGE); + + mLiveFilterLevelCombo = new Combo(c, SWT.READ_ONLY | SWT.DROP_DOWN); + mLiveFilterLevelCombo.setItems( + LogCatFilterSettingsDialog.getLogLevels().toArray(new String[0])); + mLiveFilterLevelCombo.select(0); + + ToolBar toolBar = new ToolBar(c, SWT.FLAT); + + ToolItem saveToLog = new ToolItem(toolBar, SWT.PUSH); + saveToLog.setImage(ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_SAVE_LOG_TO_FILE, + toolBar.getDisplay())); + saveToLog.setToolTipText("Export Log To Text File."); + + ToolItem clearLog = new ToolItem(toolBar, SWT.PUSH); + clearLog.setImage( + ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_CLEAR_LOG, toolBar.getDisplay())); + clearLog.setToolTipText("Clear Log"); + + ToolItem scrollToLast = new ToolItem(toolBar, SWT.PUSH); + scrollToLast.setImage( + ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_SCROLL_LOG_TO_LATEST, + toolBar.getDisplay())); + scrollToLast.setToolTipText("Always scroll to the latest output from logcat"); + + /* FIXME: Enable all the UI elements after adding support for user interaction with them. */ + mLiveFilterText.setEnabled(false); + mLiveFilterLevelCombo.setEnabled(false); + toolBar.setEnabled(false); + } + private void createLogcatViewTable(Composite parent) { /* SWT.VIRTUAL style will make the table render faster, but all rows will be * of equal heights which causes wrapped messages to just be clipped. */ final Table table = new Table(parent, SWT.FULL_SELECTION); mViewer = new TableViewer(table); - GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); - gd.horizontalSpan = 2; - mViewer.getTable().setLayoutData(gd); + table.setLayoutData(new GridData(GridData.FILL_BOTH)); table.getHorizontalBar().setVisible(true); /** Columns to show in the table. */ @@ -130,6 +395,42 @@ public final class LogCatPanel extends SelectionDependentPanel return "logcat.view.colsize." + field; } + private void setupDefaults() { + int defaultFilterIndex = 0; + mFiltersTableViewer.getTable().setSelection(defaultFilterIndex); + + filterSelectionChanged(); + } + + /** + * Perform all necessary updates whenever a filter is selected (by user or programmatically). + */ + private void filterSelectionChanged() { + int idx = mFiltersTableViewer.getTable().getSelectionIndex(); + + updateFiltersToolBar(idx); + selectFilter(idx); + } + + private void updateFiltersToolBar(int index) { + boolean en = true; + if (index == 0) { + en = false; + } + + /* The default filter at index 0 can neither be edited or removed. */ + mEditFilterToolItem.setEnabled(en); + mDeleteFilterToolItem.setEnabled(en); + } + + private void selectFilter(int index) { + assert index > 0 && index < mLogCatFilters.size(); + + mViewer.setFilters(new ViewerFilter[] { + new LogCatViewerFilter(mLogCatFilters.get(index)), + }); + } + @Override public void setFocus() { } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatViewerFilter.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatViewerFilter.java new file mode 100644 index 0000000..bfe0451 --- /dev/null +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatViewerFilter.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ddmuilib.logcat; + +import com.android.ddmlib.Log; + +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + + +/** + * A JFace {@link ViewerFilter} for the {@link LogCatPanel} displaying logcat messages. + * This can filter logcat messages based on various properties of the message. + */ +public final class LogCatViewerFilter extends ViewerFilter { + private LogCatFilterSettings mFilterSettings; + + private boolean mCheckPID; + private boolean mCheckTag; + private Pattern mTagPattern; + + /** + * Construct a {@link ViewerFilter} filtering logcat messages based on + * user provided filter settings for PID, Tag and log level. + * @param filterSettings settings to use for the filter. Invalid regexes will + * be ignored, so they should be checked for validity before constructing this object. + */ + public LogCatViewerFilter(LogCatFilterSettings filterSettings) { + mFilterSettings = filterSettings; + + mCheckPID = mFilterSettings.getPidString().trim().length() != 0; + mCheckTag = mFilterSettings.getTag().trim().length() != 0; + + if (mCheckTag) { + try { + mTagPattern = Pattern.compile(mFilterSettings.getTag()); + } catch (PatternSyntaxException e) { + Log.e("LogCatFilter", "Ignoring invalid regex."); + Log.e("LogCatFilter", e); + mCheckTag = false; + } + } + } + + @Override + public boolean select(Viewer viewer, Object parent, Object element) { + if (!(element instanceof LogCatMessage)) { + return false; + } + + LogCatMessage m = (LogCatMessage) element; + + /* filter out messages of a lower priority */ + if (m.getLogLevel().getPriority() < mFilterSettings.getLogLevel().getPriority()) { + return false; + } + + /* if pid filter is enabled, filter out messages whose pid does not match + * the filter's pid */ + if (mCheckPID && !m.getPidString().equals(mFilterSettings.getPidString())) { + return false; + } + + /* if tag filter is enabled, filter out messages not matching the tag */ + if (mCheckTag) { + Matcher matcher = mTagPattern.matcher(m.getTag()); + if (!matcher.matches()) { + return false; + } + } + + return true; + } +} |