/*
* Copyright (C) 2008 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.log.event;
import com.android.ddmlib.log.EventLogParser;
import com.android.ddmlib.log.EventValueDescription;
import com.android.ddmlib.log.EventContainer.CompareMethod;
import com.android.ddmlib.log.EventContainer.EventValueType;
import com.android.ddmuilib.log.event.EventDisplay.OccurrenceDisplayDescriptor;
import com.android.ddmuilib.log.event.EventDisplay.ValueDisplayDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
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.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
final class EventValueSelector extends Dialog {
private static final int DLG_WIDTH = 400;
private static final int DLG_HEIGHT = 300;
private Shell mParent;
private Shell mShell;
private boolean mEditStatus;
private Combo mEventCombo;
private Combo mValueCombo;
private Combo mSeriesCombo;
private Button mDisplayPidCheckBox;
private Combo mFilterCombo;
private Combo mFilterMethodCombo;
private Text mFilterValue;
private Button mOkButton;
private EventLogParser mLogParser;
private OccurrenceDisplayDescriptor mDescriptor;
/** list of event integer in the order of the combo. */
private Integer[] mEventTags;
/** list of indices in the {@link EventValueDescription} array of the current event
* that are of type string. This lets us get back the {@link EventValueDescription} from the
* index in the Series {@link Combo}.
*/
private final ArrayList<Integer> mSeriesIndices = new ArrayList<Integer>();
public EventValueSelector(Shell parent) {
super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL);
}
/**
* Opens the display option dialog to edit a new descriptor.
* @param decriptorClass the class of the object to instantiate. Must extend
* {@link OccurrenceDisplayDescriptor}
* @param logParser
* @return true if the object is to be created, false if the creation was canceled.
*/
boolean open(Class<? extends OccurrenceDisplayDescriptor> descriptorClass,
EventLogParser logParser) {
try {
OccurrenceDisplayDescriptor descriptor = descriptorClass.newInstance();
setModified();
return open(descriptor, logParser);
} catch (InstantiationException e) {
return false;
} catch (IllegalAccessException e) {
return false;
}
}
/**
* Opens the display option dialog, to edit a {@link OccurrenceDisplayDescriptor} object or
* a {@link ValueDisplayDescriptor} object.
* @param descriptor The descriptor to edit.
* @return true if the object was modified.
*/
boolean open(OccurrenceDisplayDescriptor descriptor, EventLogParser logParser) {
// make a copy of the descriptor as we'll use a working copy.
if (descriptor instanceof ValueDisplayDescriptor) {
mDescriptor = new ValueDisplayDescriptor((ValueDisplayDescriptor)descriptor);
} else if (descriptor instanceof OccurrenceDisplayDescriptor) {
mDescriptor = new OccurrenceDisplayDescriptor(descriptor);
} else {
return false;
}
mLogParser = logParser;
createUI();
if (mParent == null || mShell == null) {
return false;
}
loadValueDescriptor();
checkValidity();
// Set the dialog size.
try {
mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT);
Rectangle r = mParent.getBounds();
// get the center new top left.
int cx = r.x + r.width/2;
int x = cx - DLG_WIDTH / 2;
int cy = r.y + r.height/2;
int y = cy - DLG_HEIGHT / 2;
mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT);
} catch (Exception e) {
e.printStackTrace();
}
mShell.layout();
// actually open the dialog
mShell.open();
// event loop until the dialog is closed.
Display display = mParent.getDisplay();
while (!mShell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
return mEditStatus;
}
OccurrenceDisplayDescriptor getDescriptor() {
return mDescriptor;
}
private void createUI() {
GridData gd;
mParent = getParent();
mShell = new Shell(mParent, getStyle());
mShell.setText("Event Display Configuration");
mShell.setLayout(new GridLayout(2, false));
Label l = new Label(mShell, SWT.NONE);
l.setText("Event:");
mEventCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY);
mEventCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// the event tag / event name map
Map<Integer, String> eventTagMap = mLogParser.getTagMap();
Map<Integer, EventValueDescription[]> eventInfoMap = mLogParser.getEventInfoMap();
Set<Integer> keys = eventTagMap.keySet();
ArrayList<Integer> list = new ArrayList<Integer>();
for (Integer i : keys) {
if (eventInfoMap.get(i) != null) {
String eventName = eventTagMap.get(i);
mEventCombo.add(eventName);
list.add(i);
}
}
mEventTags = list.toArray(new Integer[list.size()]);
mEventCombo.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
handleEventComboSelection();
setModified();
}
});
l = new Label(mShell, SWT.NONE);
l.setText("Value:");
mValueCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY);
mValueCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mValueCombo.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
handleValueComboSelection();
setModified();
}
});
l = new Label(mShell, SWT.NONE);
l.setText("Series Name:");
mSeriesCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY);
mSeriesCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSeriesCombo.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
handleSeriesComboSelection();
setModified();
}
});
// empty comp
new Composite(mShell, SWT.NONE).setLayoutData(gd = new GridData());
gd.heightHint = gd.widthHint = 0;
mDisplayPidCheckBox = new Button(mShell, SWT.CHECK);
mDisplayPidCheckBox.setText("Also Show pid");
mDisplayPidCheckBox.setEnabled(false);
mDisplayPidCheckBox.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
mDescriptor.includePid = mDisplayPidCheckBox.getSelection();
setModified();
}
});
l = new Label(mShell, SWT.NONE);
l.setText("Filter By:");
mFilterCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY);
mFilterCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mFilterCombo.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
handleFilterComboSelection();
setModified();
}
});
l = new Label(mShell, SWT.NONE);
l.setText("Filter Method:");
mFilterMethodCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY);
mFilterMethodCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
for (CompareMethod method : CompareMethod.values()) {
mFilterMethodCombo.add(method.toString());
}
mFilterMethodCombo.select(0);
mFilterMethodCombo.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
handleFilterMethodComboSelection();
setModified();
}
});
l = new Label(mShell, SWT.NONE);
l.setText("Filter Value:");
mFilterValue = new Text(mShell, SWT.BORDER | SWT.SINGLE);
mFilterValue.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mFilterValue.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (mDescriptor.filterValueIndex != -1) {
// get the current selection in the event combo
int index = mEventCombo.getSelectionIndex();
if (index != -1) {
// match it to an event
int eventTag = mEventTags[index];
mDescriptor.eventTag = eventTag;
// get the EventValueDescription for this tag
EventValueDescription valueDesc = mLogParser.getEventInfoMap()
.get(eventTag)[mDescriptor.filterValueIndex];
// let the EventValueDescription convert the String value into an object
// of the proper type.
mDescriptor.filterValue = valueDesc.getObjectFromString(
mFilterValue.getText().trim());
setModified();
}
}
}
});
// add a separator spanning the 2 columns
l = new Label(mShell, SWT.SEPARATOR | SWT.HORIZONTAL);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
l.setLayoutData(gd);
// add a composite to hold the ok/cancel button, no matter what the columns size are.
Composite buttonComp = new Composite(mShell, SWT.NONE);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
buttonComp.setLayoutData(gd);
GridLayout gl;
buttonComp.setLayout(gl = new GridLayout(6, true));
gl.marginHeight = gl.marginWidth = 0;
Composite padding = new Composite(mShell, SWT.NONE);
padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mOkButton = new Button(buttonComp, SWT.PUSH);
mOkButton.setText("OK");
mOkButton.setLayoutData(new GridData(GridData.CENTER));
mOkButton.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
mShell.close();
}
});
padding = new Composite(mShell, SWT.NONE);
padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
padding = new Composite(mShell, SWT.NONE);
padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Button cancelButton = new Button(buttonComp, SWT.PUSH);
cancelButton.setText("Cancel");
cancelButton.setLayoutData(new GridData(GridData.CENTER));
cancelButton.addSelectionListener(new SelectionAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
// cancel the edit
mEditStatus = false;
mShell.close();
}
});
padding = new Composite(mShell, SWT.NONE);
padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mShell.addListener(SWT.Close, new Listener() {
public void handleEvent(Event event) {
event.doit = true;
}
});
}
private void setModified() {
mEditStatus = true;
}
private void handleEventComboSelection() {
// get the current selection in the event combo
int index = mEventCombo.getSelectionIndex();
if (index != -1) {
// match it to an event
int eventTag = mEventTags[index];
mDescriptor.eventTag = eventTag;
// get the EventValueDescription for this tag
EventValueDescription[] values = mLogParser.getEventInfoMap().get(eventTag);
// fill the combo for the values
mValueCombo.removeAll();
if (values != null) {
if (mDescriptor instanceof ValueDisplayDescriptor) {
ValueDisplayDescriptor valueDescriptor = (ValueDisplayDescriptor)mDescriptor;
mValueCombo.setEnabled(true);
for (EventValueDescription value : values) {
mValueCombo.add(value.toString());
}
if (valueDescriptor.valueIndex != -1) {
mValueCombo.select(valueDescriptor.valueIndex);
} else {
mValueCombo.clearSelection();
}
} else {
mValueCombo.setEnabled(false);
}
// fill the axis combo
mSeriesCombo.removeAll();
mSeriesCombo.setEnabled(false);
mSeriesIndices.clear();
int axisIndex = 0;
int selectionIndex = -1;
for (EventValueDescription value : values) {
if (value.getEventValueType() == EventValueType.STRING) {
mSeriesCombo.add(value.getName());
mSeriesCombo.setEnabled(true);
mSeriesIndices.add(axisIndex);
if (mDescriptor.seriesValueIndex != -1 &&
mDescriptor.seriesValueIndex == axisIndex) {
selectionIndex = axisIndex;
}
}
axisIndex++;
}
if (mSeriesCombo.isEnabled()) {
mSeriesCombo.add("default (pid)", 0 /* index */);
mSeriesIndices.add(0 /* index */, -1 /* value */);
// +1 because we added another item at index 0
mSeriesCombo.select(selectionIndex + 1);
if (selectionIndex >= 0) {
mDisplayPidCheckBox.setSelection(mDescriptor.includePid);
mDisplayPidCheckBox.setEnabled(true);
} else {
mDisplayPidCheckBox.setEnabled(false);
mDisplayPidCheckBox.setSelection(false);
}
} else {
mDisplayPidCheckBox.setSelection(false);
mDisplayPidCheckBox.setEnabled(false);
}
// fill the filter combo
mFilterCombo.setEnabled(true);
mFilterCombo.removeAll();
mFilterCombo.add("(no filter)");
for (EventValueDescription value : values) {
mFilterCombo.add(value.toString());
}
// select the current filter
mFilterCombo.select(mDescriptor.filterValueIndex + 1);
mFilterMethodCombo.select(getFilterMethodIndex(mDescriptor.filterCompareMethod));
// fill the current filter value
if (mDescriptor.filterValueIndex != -1) {
EventValueDescription valueInfo = values[mDescriptor.filterValueIndex];
if (valueInfo.checkForType(mDescriptor.filterValue)) {
mFilterValue.setText(mDescriptor.filterValue.toString());
} else {
mFilterValue.setText("");
}
} else {
mFilterValue.setText("");
}
} else {
disableSubCombos();
}
} else {
disableSubCombos();
}
checkValidity();
}
/**
*
*/
private void disableSubCombos() {
mValueCombo.removeAll();
mValueCombo.clearSelection();
mValueCombo.setEnabled(false);
mSeriesCombo.removeAll();
mSeriesCombo.clearSelection();
mSeriesCombo.setEnabled(false);
mDisplayPidCheckBox.setEnabled(false);
mDisplayPidCheckBox.setSelection(false);
mFilterCombo.removeAll();
mFilterCombo.clearSelection();
mFilterCombo.setEnabled(false);
mFilterValue.setEnabled(false);
mFilterValue.setText("");
mFilterMethodCombo.setEnabled(false);
}
private void handleValueComboSelection() {
ValueDisplayDescriptor valueDescriptor = (ValueDisplayDescriptor)mDescriptor;
// get the current selection in the value combo
int index = mValueCombo.getSelectionIndex();
valueDescriptor.valueIndex = index;
// for now set the built-in name
// get the current selection in the event combo
int eventIndex = mEventCombo.getSelectionIndex();
// match it to an event
int eventTag = mEventTags[eventIndex];
// get the EventValueDescription for this tag
EventValueDescription[] values = mLogParser.getEventInfoMap().get(eventTag);
valueDescriptor.valueName = values[index].getName();
checkValidity();
}
private void handleSeriesComboSelection() {
// get the current selection in the axis combo
int index = mSeriesCombo.getSelectionIndex();
// get the actual value index from the list.
int valueIndex = mSeriesIndices.get(index);
mDescriptor.seriesValueIndex = valueIndex;
if (index > 0) {
mDisplayPidCheckBox.setEnabled(true);
mDisplayPidCheckBox.setSelection(mDescriptor.includePid);
} else {
mDisplayPidCheckBox.setSelection(false);
mDisplayPidCheckBox.setEnabled(false);
}
}
private void handleFilterComboSelection() {
// get the current selection in the axis combo
int index = mFilterCombo.getSelectionIndex();
// decrement index by 1 since the item 0 means
// no filter (index = -1), and the rest is offset by 1
index--;
mDescriptor.filterValueIndex = index;
if (index != -1) {
mFilterValue.setEnabled(true);
mFilterMethodCombo.setEnabled(true);
if (mDescriptor.filterValue instanceof String) {
mFilterValue.setText((String)mDescriptor.filterValue);
}
} else {
mFilterValue.setText("");
mFilterValue.setEnabled(false);
mFilterMethodCombo.setEnabled(false);
}
}
private void handleFilterMethodComboSelection() {
// get the current selection in the axis combo
int index = mFilterMethodCombo.getSelectionIndex();
CompareMethod method = CompareMethod.values()[index];
mDescriptor.filterCompareMethod = method;
}
/**
* Returns the index of the filter method
* @param filterCompareMethod the {@link CompareMethod} enum.
*/
private int getFilterMethodIndex(CompareMethod filterCompareMethod) {
CompareMethod[] values = CompareMethod.values();
for (int i = 0 ; i < values.length ; i++) {
if (values[i] == filterCompareMethod) {
return i;
}
}
return -1;
}
private void loadValueDescriptor() {
// get the index from the eventTag.
int eventIndex = 0;
int comboIndex = -1;
for (int i : mEventTags) {
if (i == mDescriptor.eventTag) {
comboIndex = eventIndex;
break;
}
eventIndex++;
}
if (comboIndex == -1) {
mEventCombo.clearSelection();
} else {
mEventCombo.select(comboIndex);
}
// get the event from the descriptor
handleEventComboSelection();
}
private void checkValidity() {
mOkButton.setEnabled(mEventCombo.getSelectionIndex() != -1 &&
(((mDescriptor instanceof ValueDisplayDescriptor) == false) ||
mValueCombo.getSelectionIndex() != -1));
}
}