aboutsummaryrefslogtreecommitdiffstats
path: root/ddms
diff options
context:
space:
mode:
authorSiva Velusamy <vsiva@google.com>2011-08-09 13:31:40 -0700
committerSiva Velusamy <vsiva@google.com>2011-08-10 17:01:29 -0700
commitac6aaab3abe0e42f3090975c3a2d6f994bec8f2c (patch)
treee4b5f98904dfee63615592faa34dc77bc65327d9 /ddms
parentb812a9a0c7e9b7fb87c4d4c6769fc9a6f8740fad (diff)
downloadsdk-ac6aaab3abe0e42f3090975c3a2d6f994bec8f2c.zip
sdk-ac6aaab3abe0e42f3090975c3a2d6f994bec8f2c.tar.gz
sdk-ac6aaab3abe0e42f3090975c3a2d6f994bec8f2c.tar.bz2
Add support for filtering logcat messages.
In the logcat view, add a panel on the side where users can create/edit/delete filters for logcat messages. Users can filter by the message tag, pid or loglevel. Change-Id: Ic85397794e5437b761b91a74adb0dd6a58bc74ed
Diffstat (limited to 'ddms')
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java45
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java54
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettings.java51
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java269
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java313
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatViewerFilter.java91
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;
+ }
+}