1 /* 2 * Copyright (C) 2008 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.ddmuilib.log.event; 18 19 import com.android.ddmlib.log.EventContainer.CompareMethod; 20 import com.android.ddmlib.log.EventContainer.EventValueType; 21 import com.android.ddmlib.log.EventLogParser; 22 import com.android.ddmlib.log.EventValueDescription; 23 import com.android.ddmuilib.log.event.EventDisplay.OccurrenceDisplayDescriptor; 24 import com.android.ddmuilib.log.event.EventDisplay.ValueDisplayDescriptor; 25 26 import org.eclipse.swt.SWT; 27 import org.eclipse.swt.events.ModifyEvent; 28 import org.eclipse.swt.events.ModifyListener; 29 import org.eclipse.swt.events.SelectionAdapter; 30 import org.eclipse.swt.events.SelectionEvent; 31 import org.eclipse.swt.graphics.Rectangle; 32 import org.eclipse.swt.layout.GridData; 33 import org.eclipse.swt.layout.GridLayout; 34 import org.eclipse.swt.widgets.Button; 35 import org.eclipse.swt.widgets.Combo; 36 import org.eclipse.swt.widgets.Composite; 37 import org.eclipse.swt.widgets.Dialog; 38 import org.eclipse.swt.widgets.Display; 39 import org.eclipse.swt.widgets.Event; 40 import org.eclipse.swt.widgets.Label; 41 import org.eclipse.swt.widgets.Listener; 42 import org.eclipse.swt.widgets.Shell; 43 import org.eclipse.swt.widgets.Text; 44 45 import java.util.ArrayList; 46 import java.util.Map; 47 import java.util.Set; 48 49 final class EventValueSelector extends Dialog { 50 private static final int DLG_WIDTH = 400; 51 private static final int DLG_HEIGHT = 300; 52 53 private Shell mParent; 54 private Shell mShell; 55 private boolean mEditStatus; 56 private Combo mEventCombo; 57 private Combo mValueCombo; 58 private Combo mSeriesCombo; 59 private Button mDisplayPidCheckBox; 60 private Combo mFilterCombo; 61 private Combo mFilterMethodCombo; 62 private Text mFilterValue; 63 private Button mOkButton; 64 65 private EventLogParser mLogParser; 66 private OccurrenceDisplayDescriptor mDescriptor; 67 68 /** list of event integer in the order of the combo. */ 69 private Integer[] mEventTags; 70 71 /** list of indices in the {@link EventValueDescription} array of the current event 72 * that are of type string. This lets us get back the {@link EventValueDescription} from the 73 * index in the Series {@link Combo}. 74 */ 75 private final ArrayList<Integer> mSeriesIndices = new ArrayList<Integer>(); 76 77 public EventValueSelector(Shell parent) { 78 super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL); 79 } 80 81 /** 82 * Opens the display option dialog to edit a new descriptor. 83 * @param decriptorClass the class of the object to instantiate. Must extend 84 * {@link OccurrenceDisplayDescriptor} 85 * @param logParser 86 * @return true if the object is to be created, false if the creation was canceled. 87 */ 88 boolean open(Class<? extends OccurrenceDisplayDescriptor> descriptorClass, 89 EventLogParser logParser) { 90 try { 91 OccurrenceDisplayDescriptor descriptor = descriptorClass.newInstance(); 92 setModified(); 93 return open(descriptor, logParser); 94 } catch (InstantiationException e) { 95 return false; 96 } catch (IllegalAccessException e) { 97 return false; 98 } 99 } 100 101 /** 102 * Opens the display option dialog, to edit a {@link OccurrenceDisplayDescriptor} object or 103 * a {@link ValueDisplayDescriptor} object. 104 * @param descriptor The descriptor to edit. 105 * @return true if the object was modified. 106 */ 107 boolean open(OccurrenceDisplayDescriptor descriptor, EventLogParser logParser) { 108 // make a copy of the descriptor as we'll use a working copy. 109 if (descriptor instanceof ValueDisplayDescriptor) { 110 mDescriptor = new ValueDisplayDescriptor((ValueDisplayDescriptor)descriptor); 111 } else if (descriptor instanceof OccurrenceDisplayDescriptor) { 112 mDescriptor = new OccurrenceDisplayDescriptor(descriptor); 113 } else { 114 return false; 115 } 116 117 mLogParser = logParser; 118 119 createUI(); 120 121 if (mParent == null || mShell == null) { 122 return false; 123 } 124 125 loadValueDescriptor(); 126 127 checkValidity(); 128 129 // Set the dialog size. 130 try { 131 mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT); 132 Rectangle r = mParent.getBounds(); 133 // get the center new top left. 134 int cx = r.x + r.width/2; 135 int x = cx - DLG_WIDTH / 2; 136 int cy = r.y + r.height/2; 137 int y = cy - DLG_HEIGHT / 2; 138 mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT); 139 } catch (Exception e) { 140 e.printStackTrace(); 141 } 142 143 mShell.layout(); 144 145 // actually open the dialog 146 mShell.open(); 147 148 // event loop until the dialog is closed. 149 Display display = mParent.getDisplay(); 150 while (!mShell.isDisposed()) { 151 if (!display.readAndDispatch()) 152 display.sleep(); 153 } 154 155 return mEditStatus; 156 } 157 158 OccurrenceDisplayDescriptor getDescriptor() { 159 return mDescriptor; 160 } 161 162 private void createUI() { 163 GridData gd; 164 165 mParent = getParent(); 166 mShell = new Shell(mParent, getStyle()); 167 mShell.setText("Event Display Configuration"); 168 169 mShell.setLayout(new GridLayout(2, false)); 170 171 Label l = new Label(mShell, SWT.NONE); 172 l.setText("Event:"); 173 174 mEventCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); 175 mEventCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 176 177 // the event tag / event name map 178 Map<Integer, String> eventTagMap = mLogParser.getTagMap(); 179 Map<Integer, EventValueDescription[]> eventInfoMap = mLogParser.getEventInfoMap(); 180 Set<Integer> keys = eventTagMap.keySet(); 181 ArrayList<Integer> list = new ArrayList<Integer>(); 182 for (Integer i : keys) { 183 if (eventInfoMap.get(i) != null) { 184 String eventName = eventTagMap.get(i); 185 mEventCombo.add(eventName); 186 187 list.add(i); 188 } 189 } 190 mEventTags = list.toArray(new Integer[list.size()]); 191 192 mEventCombo.addSelectionListener(new SelectionAdapter() { 193 /* (non-Javadoc) 194 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 195 */ 196 @Override 197 public void widgetSelected(SelectionEvent e) { 198 handleEventComboSelection(); 199 setModified(); 200 } 201 }); 202 203 l = new Label(mShell, SWT.NONE); 204 l.setText("Value:"); 205 206 mValueCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); 207 mValueCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 208 mValueCombo.addSelectionListener(new SelectionAdapter() { 209 /* (non-Javadoc) 210 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 211 */ 212 @Override 213 public void widgetSelected(SelectionEvent e) { 214 handleValueComboSelection(); 215 setModified(); 216 } 217 }); 218 219 l = new Label(mShell, SWT.NONE); 220 l.setText("Series Name:"); 221 222 mSeriesCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); 223 mSeriesCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 224 mSeriesCombo.addSelectionListener(new SelectionAdapter() { 225 /* (non-Javadoc) 226 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 227 */ 228 @Override 229 public void widgetSelected(SelectionEvent e) { 230 handleSeriesComboSelection(); 231 setModified(); 232 } 233 }); 234 235 // empty comp 236 new Composite(mShell, SWT.NONE).setLayoutData(gd = new GridData()); 237 gd.heightHint = gd.widthHint = 0; 238 239 mDisplayPidCheckBox = new Button(mShell, SWT.CHECK); 240 mDisplayPidCheckBox.setText("Also Show pid"); 241 mDisplayPidCheckBox.setEnabled(false); 242 mDisplayPidCheckBox.addSelectionListener(new SelectionAdapter() { 243 /* (non-Javadoc) 244 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 245 */ 246 @Override 247 public void widgetSelected(SelectionEvent e) { 248 mDescriptor.includePid = mDisplayPidCheckBox.getSelection(); 249 setModified(); 250 } 251 }); 252 253 l = new Label(mShell, SWT.NONE); 254 l.setText("Filter By:"); 255 256 mFilterCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); 257 mFilterCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 258 mFilterCombo.addSelectionListener(new SelectionAdapter() { 259 /* (non-Javadoc) 260 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 261 */ 262 @Override 263 public void widgetSelected(SelectionEvent e) { 264 handleFilterComboSelection(); 265 setModified(); 266 } 267 }); 268 269 l = new Label(mShell, SWT.NONE); 270 l.setText("Filter Method:"); 271 272 mFilterMethodCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); 273 mFilterMethodCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 274 for (CompareMethod method : CompareMethod.values()) { 275 mFilterMethodCombo.add(method.toString()); 276 } 277 mFilterMethodCombo.select(0); 278 mFilterMethodCombo.addSelectionListener(new SelectionAdapter() { 279 /* (non-Javadoc) 280 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 281 */ 282 @Override 283 public void widgetSelected(SelectionEvent e) { 284 handleFilterMethodComboSelection(); 285 setModified(); 286 } 287 }); 288 289 l = new Label(mShell, SWT.NONE); 290 l.setText("Filter Value:"); 291 292 mFilterValue = new Text(mShell, SWT.BORDER | SWT.SINGLE); 293 mFilterValue.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 294 mFilterValue.addModifyListener(new ModifyListener() { 295 @Override 296 public void modifyText(ModifyEvent e) { 297 if (mDescriptor.filterValueIndex != -1) { 298 // get the current selection in the event combo 299 int index = mEventCombo.getSelectionIndex(); 300 301 if (index != -1) { 302 // match it to an event 303 int eventTag = mEventTags[index]; 304 mDescriptor.eventTag = eventTag; 305 306 // get the EventValueDescription for this tag 307 EventValueDescription valueDesc = mLogParser.getEventInfoMap() 308 .get(eventTag)[mDescriptor.filterValueIndex]; 309 310 // let the EventValueDescription convert the String value into an object 311 // of the proper type. 312 mDescriptor.filterValue = valueDesc.getObjectFromString( 313 mFilterValue.getText().trim()); 314 setModified(); 315 } 316 } 317 } 318 }); 319 320 // add a separator spanning the 2 columns 321 322 l = new Label(mShell, SWT.SEPARATOR | SWT.HORIZONTAL); 323 gd = new GridData(GridData.FILL_HORIZONTAL); 324 gd.horizontalSpan = 2; 325 l.setLayoutData(gd); 326 327 // add a composite to hold the ok/cancel button, no matter what the columns size are. 328 Composite buttonComp = new Composite(mShell, SWT.NONE); 329 gd = new GridData(GridData.FILL_HORIZONTAL); 330 gd.horizontalSpan = 2; 331 buttonComp.setLayoutData(gd); 332 GridLayout gl; 333 buttonComp.setLayout(gl = new GridLayout(6, true)); 334 gl.marginHeight = gl.marginWidth = 0; 335 336 Composite padding = new Composite(mShell, SWT.NONE); 337 padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 338 339 mOkButton = new Button(buttonComp, SWT.PUSH); 340 mOkButton.setText("OK"); 341 mOkButton.setLayoutData(new GridData(GridData.CENTER)); 342 mOkButton.addSelectionListener(new SelectionAdapter() { 343 /* (non-Javadoc) 344 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 345 */ 346 @Override 347 public void widgetSelected(SelectionEvent e) { 348 mShell.close(); 349 } 350 }); 351 352 padding = new Composite(mShell, SWT.NONE); 353 padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 354 355 padding = new Composite(mShell, SWT.NONE); 356 padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 357 358 Button cancelButton = new Button(buttonComp, SWT.PUSH); 359 cancelButton.setText("Cancel"); 360 cancelButton.setLayoutData(new GridData(GridData.CENTER)); 361 cancelButton.addSelectionListener(new SelectionAdapter() { 362 /* (non-Javadoc) 363 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) 364 */ 365 @Override 366 public void widgetSelected(SelectionEvent e) { 367 // cancel the edit 368 mEditStatus = false; 369 mShell.close(); 370 } 371 }); 372 373 padding = new Composite(mShell, SWT.NONE); 374 padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 375 376 mShell.addListener(SWT.Close, new Listener() { 377 @Override 378 public void handleEvent(Event event) { 379 event.doit = true; 380 } 381 }); 382 } 383 384 private void setModified() { 385 mEditStatus = true; 386 } 387 388 private void handleEventComboSelection() { 389 // get the current selection in the event combo 390 int index = mEventCombo.getSelectionIndex(); 391 392 if (index != -1) { 393 // match it to an event 394 int eventTag = mEventTags[index]; 395 mDescriptor.eventTag = eventTag; 396 397 // get the EventValueDescription for this tag 398 EventValueDescription[] values = mLogParser.getEventInfoMap().get(eventTag); 399 400 // fill the combo for the values 401 mValueCombo.removeAll(); 402 if (values != null) { 403 if (mDescriptor instanceof ValueDisplayDescriptor) { 404 ValueDisplayDescriptor valueDescriptor = (ValueDisplayDescriptor)mDescriptor; 405 406 mValueCombo.setEnabled(true); 407 for (EventValueDescription value : values) { 408 mValueCombo.add(value.toString()); 409 } 410 411 if (valueDescriptor.valueIndex != -1) { 412 mValueCombo.select(valueDescriptor.valueIndex); 413 } else { 414 mValueCombo.clearSelection(); 415 } 416 } else { 417 mValueCombo.setEnabled(false); 418 } 419 420 // fill the axis combo 421 mSeriesCombo.removeAll(); 422 mSeriesCombo.setEnabled(false); 423 mSeriesIndices.clear(); 424 int axisIndex = 0; 425 int selectionIndex = -1; 426 for (EventValueDescription value : values) { 427 if (value.getEventValueType() == EventValueType.STRING) { 428 mSeriesCombo.add(value.getName()); 429 mSeriesCombo.setEnabled(true); 430 mSeriesIndices.add(axisIndex); 431 432 if (mDescriptor.seriesValueIndex != -1 && 433 mDescriptor.seriesValueIndex == axisIndex) { 434 selectionIndex = axisIndex; 435 } 436 } 437 axisIndex++; 438 } 439 440 if (mSeriesCombo.isEnabled()) { 441 mSeriesCombo.add("default (pid)", 0 /* index */); 442 mSeriesIndices.add(0 /* index */, -1 /* value */); 443 444 // +1 because we added another item at index 0 445 mSeriesCombo.select(selectionIndex + 1); 446 447 if (selectionIndex >= 0) { 448 mDisplayPidCheckBox.setSelection(mDescriptor.includePid); 449 mDisplayPidCheckBox.setEnabled(true); 450 } else { 451 mDisplayPidCheckBox.setEnabled(false); 452 mDisplayPidCheckBox.setSelection(false); 453 } 454 } else { 455 mDisplayPidCheckBox.setSelection(false); 456 mDisplayPidCheckBox.setEnabled(false); 457 } 458 459 // fill the filter combo 460 mFilterCombo.setEnabled(true); 461 mFilterCombo.removeAll(); 462 mFilterCombo.add("(no filter)"); 463 for (EventValueDescription value : values) { 464 mFilterCombo.add(value.toString()); 465 } 466 467 // select the current filter 468 mFilterCombo.select(mDescriptor.filterValueIndex + 1); 469 mFilterMethodCombo.select(getFilterMethodIndex(mDescriptor.filterCompareMethod)); 470 471 // fill the current filter value 472 if (mDescriptor.filterValueIndex != -1) { 473 EventValueDescription valueInfo = values[mDescriptor.filterValueIndex]; 474 if (valueInfo.checkForType(mDescriptor.filterValue)) { 475 mFilterValue.setText(mDescriptor.filterValue.toString()); 476 } else { 477 mFilterValue.setText(""); 478 } 479 } else { 480 mFilterValue.setText(""); 481 } 482 } else { 483 disableSubCombos(); 484 } 485 } else { 486 disableSubCombos(); 487 } 488 489 checkValidity(); 490 } 491 492 /** 493 * 494 */ 495 private void disableSubCombos() { 496 mValueCombo.removeAll(); 497 mValueCombo.clearSelection(); 498 mValueCombo.setEnabled(false); 499 500 mSeriesCombo.removeAll(); 501 mSeriesCombo.clearSelection(); 502 mSeriesCombo.setEnabled(false); 503 504 mDisplayPidCheckBox.setEnabled(false); 505 mDisplayPidCheckBox.setSelection(false); 506 507 mFilterCombo.removeAll(); 508 mFilterCombo.clearSelection(); 509 mFilterCombo.setEnabled(false); 510 511 mFilterValue.setEnabled(false); 512 mFilterValue.setText(""); 513 mFilterMethodCombo.setEnabled(false); 514 } 515 516 private void handleValueComboSelection() { 517 ValueDisplayDescriptor valueDescriptor = (ValueDisplayDescriptor)mDescriptor; 518 519 // get the current selection in the value combo 520 int index = mValueCombo.getSelectionIndex(); 521 valueDescriptor.valueIndex = index; 522 523 // for now set the built-in name 524 525 // get the current selection in the event combo 526 int eventIndex = mEventCombo.getSelectionIndex(); 527 528 // match it to an event 529 int eventTag = mEventTags[eventIndex]; 530 531 // get the EventValueDescription for this tag 532 EventValueDescription[] values = mLogParser.getEventInfoMap().get(eventTag); 533 534 valueDescriptor.valueName = values[index].getName(); 535 536 checkValidity(); 537 } 538 539 private void handleSeriesComboSelection() { 540 // get the current selection in the axis combo 541 int index = mSeriesCombo.getSelectionIndex(); 542 543 // get the actual value index from the list. 544 int valueIndex = mSeriesIndices.get(index); 545 546 mDescriptor.seriesValueIndex = valueIndex; 547 548 if (index > 0) { 549 mDisplayPidCheckBox.setEnabled(true); 550 mDisplayPidCheckBox.setSelection(mDescriptor.includePid); 551 } else { 552 mDisplayPidCheckBox.setSelection(false); 553 mDisplayPidCheckBox.setEnabled(false); 554 } 555 } 556 557 private void handleFilterComboSelection() { 558 // get the current selection in the axis combo 559 int index = mFilterCombo.getSelectionIndex(); 560 561 // decrement index by 1 since the item 0 means 562 // no filter (index = -1), and the rest is offset by 1 563 index--; 564 565 mDescriptor.filterValueIndex = index; 566 567 if (index != -1) { 568 mFilterValue.setEnabled(true); 569 mFilterMethodCombo.setEnabled(true); 570 if (mDescriptor.filterValue instanceof String) { 571 mFilterValue.setText((String)mDescriptor.filterValue); 572 } 573 } else { 574 mFilterValue.setText(""); 575 mFilterValue.setEnabled(false); 576 mFilterMethodCombo.setEnabled(false); 577 } 578 } 579 580 private void handleFilterMethodComboSelection() { 581 // get the current selection in the axis combo 582 int index = mFilterMethodCombo.getSelectionIndex(); 583 CompareMethod method = CompareMethod.values()[index]; 584 585 mDescriptor.filterCompareMethod = method; 586 } 587 588 /** 589 * Returns the index of the filter method 590 * @param filterCompareMethod the {@link CompareMethod} enum. 591 */ 592 private int getFilterMethodIndex(CompareMethod filterCompareMethod) { 593 CompareMethod[] values = CompareMethod.values(); 594 for (int i = 0 ; i < values.length ; i++) { 595 if (values[i] == filterCompareMethod) { 596 return i; 597 } 598 } 599 return -1; 600 } 601 602 603 private void loadValueDescriptor() { 604 // get the index from the eventTag. 605 int eventIndex = 0; 606 int comboIndex = -1; 607 for (int i : mEventTags) { 608 if (i == mDescriptor.eventTag) { 609 comboIndex = eventIndex; 610 break; 611 } 612 eventIndex++; 613 } 614 615 if (comboIndex == -1) { 616 mEventCombo.clearSelection(); 617 } else { 618 mEventCombo.select(comboIndex); 619 } 620 621 // get the event from the descriptor 622 handleEventComboSelection(); 623 } 624 625 private void checkValidity() { 626 mOkButton.setEnabled(mEventCombo.getSelectionIndex() != -1 && 627 (((mDescriptor instanceof ValueDisplayDescriptor) == false) || 628 mValueCombo.getSelectionIndex() != -1)); 629 } 630 } 631