1 /******************************************************************************* 2 * Copyright (c) 2000, 2009 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.test.internal.performance.results.ui; 12 13 import java.util.StringTokenizer; 14 15 import org.eclipse.core.runtime.preferences.IEclipsePreferences; 16 import org.eclipse.core.runtime.preferences.InstanceScope; 17 import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; 18 import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; 19 import org.eclipse.jface.action.Action; 20 import org.eclipse.jface.action.IAction; 21 import org.eclipse.jface.action.IMenuManager; 22 import org.eclipse.jface.action.IToolBarManager; 23 import org.eclipse.jface.action.MenuManager; 24 import org.eclipse.jface.action.Separator; 25 import org.eclipse.jface.resource.ImageDescriptor; 26 import org.eclipse.jface.resource.JFaceResources; 27 import org.eclipse.jface.viewers.ISelectionChangedListener; 28 import org.eclipse.jface.viewers.SelectionChangedEvent; 29 import org.eclipse.jface.viewers.TreeSelection; 30 import org.eclipse.swt.SWT; 31 import org.eclipse.swt.custom.CTabFolder; 32 import org.eclipse.swt.custom.CTabItem; 33 import org.eclipse.swt.widgets.Composite; 34 import org.eclipse.swt.widgets.Display; 35 import org.eclipse.swt.widgets.Table; 36 import org.eclipse.test.internal.performance.results.model.BuildResultsElement; 37 import org.eclipse.test.internal.performance.results.model.ComponentResultsElement; 38 import org.eclipse.test.internal.performance.results.model.ConfigResultsElement; 39 import org.eclipse.test.internal.performance.results.model.DimResultsElement; 40 import org.eclipse.test.internal.performance.results.model.PerformanceResultsElement; 41 import org.eclipse.test.internal.performance.results.model.ResultsElement; 42 import org.eclipse.test.internal.performance.results.model.ScenarioResultsElement; 43 import org.eclipse.test.internal.performance.results.utils.IPerformancesConstants; 44 import org.eclipse.test.internal.performance.results.utils.Util; 45 import org.eclipse.ui.IActionBars; 46 import org.eclipse.ui.IMemento; 47 import org.eclipse.ui.IViewSite; 48 import org.eclipse.ui.PartInitException; 49 import org.eclipse.ui.PlatformUI; 50 import org.eclipse.ui.part.ViewPart; 51 52 53 /** 54 * This view show for each performance machine the results of all builds 55 * run since the beginning of the current version development. 56 * <p> 57 * Each machine results are show in a separate tab. 58 * </p><p> 59 * There's no real action available action from this view, only the possibility 60 * to change how is displayed the line selection (full or only first column) 61 * and also filter the results: 62 * <ul> 63 * <li>Filter for builds: 64 * <ul> 65 * <li>Filter nightly: hide the nightly builds (starting with 'N')</li> 66 * <li>Filter non-important builds: hide all non-important builds, which means non-milestone builds and those after the last milestone</li> 67 * </ul> 68 * </li> 69 * </li>Filter for scenarios: 70 * <ul> 71 * <li>Filter non-fingerprints: hide the scenarios which are not in the fingerprints</li> 72 * </ul> 73 * </li> 74 * </ul> 75 * </p><p> 76 * Note that these filters are synchronized with the ones applied in the 77 * {@link ComponentsView Components view}. 78 * </p> 79 * 80 * @see ConfigTab Folder tab containing all the results for a configuration. 81 */ 82 public class ComponentResultsView extends ViewPart implements ISelectionChangedListener, IPreferenceChangeListener { 83 84 // Constants 85 private static final String ORG_ECLIPSE = "org.eclipse."; 86 87 // SWT resources 88 CTabFolder tabFolder; 89 90 // Model information 91 ConfigTab[] tabs; 92 ComponentResultsElement componentResultsElement; 93 94 // Action 95 Action fullLineSelection; 96 Action filterAdvancedScenarios; 97 Action filterOldBuilds; 98 Action filterNightlyBuilds; 99 ImageDescriptor fullSelectionImageDescriptor; 100 101 // Views 102 IMemento viewState; 103 104 // Eclipse preferences 105 IEclipsePreferences preferences; 106 107 /* 108 * Default constructor: 109 * - create the image descriptor 110 * - register the view as a properties listener 111 */ 112 public ComponentResultsView() { 113 this.fullSelectionImageDescriptor = ImageDescriptor.createFromFile(getClass(), "icallout_obj.gif"); 114 this.preferences = new InstanceScope().getNode(IPerformancesConstants.PLUGIN_ID); 115 this.preferences.addPreferenceChangeListener(this); 116 Util.initMilestones(this.preferences); 117 } 118 119 /* 120 * Contribute the local tools bar and the pull-down menu to the action bars. 121 */ 122 void contributeToActionBars() { 123 IActionBars bars = getViewSite().getActionBars(); 124 fillLocalPullDown(bars.getMenuManager()); 125 fillLocalToolBar(bars.getToolBarManager()); 126 } 127 128 /* 129 * (non-Javadoc) 130 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) 131 */ 132 public void createPartControl(Composite parent) { 133 134 // Create the tab folder 135 this.tabFolder = new CTabFolder(parent, SWT.BORDER); 136 137 // Add results view as listener to viewer selection changes 138 Display.getDefault().asyncExec(new Runnable() { 139 public void run() { 140 PerformancesView performancesView = (PerformancesView) PerformancesView.getWorkbenchView("org.eclipse.test.internal.performance.results.ui.ComponentsView"); 141 if (performancesView != null) { 142 performancesView.viewer.addSelectionChangedListener(ComponentResultsView.this); 143 } 144 } 145 }); 146 147 // Set actions 148 PlatformUI.getWorkbench().getHelpSystem().setHelp(this.tabFolder, "org.eclipse.test.performance.ui.results"); 149 makeActions(); 150 contributeToActionBars(); 151 152 // Restore state 153 restoreState(); 154 155 // Create tabs 156 createTabs(); 157 158 // Set selections (tab and line) 159 this.tabFolder.setSimple(false); 160 } 161 162 /* 163 * Create the tab folder pages. There's one tab per performance machine. 164 * The list of these machines is got from the DB_Results contants. 165 */ 166 void createTabs() { 167 if (this.componentResultsElement == null) return; 168 PerformanceResultsElement performanceResultsElement = (PerformanceResultsElement) this.componentResultsElement.getParent(null); 169 String[] configNames = performanceResultsElement.getConfigs(); 170 String[] configDescriptions = performanceResultsElement.getConfigDescriptions(); 171 int length = configNames.length; 172 this.tabs = new ConfigTab[length]; 173 for (int i=0; i<length; i++) { 174 this.tabs[i] = new ConfigTab(configNames[i], configDescriptions[i]); 175 } 176 for (int i=0; i<this.tabs.length; i++) { 177 CTabItem item = new CTabItem (this.tabFolder, SWT.NONE); 178 item.setText (this.tabs[i].getTabText ()); 179 item.setControl (this.tabs[i].createTabFolderPage(this.componentResultsElement, this.tabFolder, this.fullLineSelection.isChecked())); 180 item.setData (this.tabs[i]); 181 } 182 this.tabFolder.setSelection(0); 183 } 184 185 /* 186 * (non-Javadoc) 187 * @see org.eclipse.ui.part.WorkbenchPart#dispose() 188 */ 189 public void dispose() { 190 this.tabFolder.dispose(); 191 int length = this.tabs==null ? 0 : this.tabs.length; 192 for (int i=0; i<length; i++) { 193 this.tabs[i].dispose(); 194 } 195 JFaceResources.getResources().destroyImage(this.fullSelectionImageDescriptor); 196 super.dispose(); 197 } 198 199 /* 200 * Fill the filters drop-down menu with: 201 * - filter nightly builds 202 * - filter non-milestone builds 203 * - filter non-fingerprint scenarios 204 */ 205 void fillFiltersDropDown(IMenuManager manager) { 206 manager.add(this.filterNightlyBuilds); 207 manager.add(this.filterOldBuilds); 208 manager.add(new Separator()); 209 manager.add(this.filterAdvancedScenarios); 210 } 211 212 /* 213 * Fill the local pull down menu. 214 */ 215 void fillLocalPullDown(IMenuManager manager) { 216 MenuManager filtersManager= new MenuManager("Filters"); 217 fillFiltersDropDown(filtersManager); 218 manager.add(filtersManager); 219 } 220 221 /* 222 * Fill the local tool bar with: 223 * - change line selection display 224 */ 225 void fillLocalToolBar(IToolBarManager manager) { 226 manager.add(this.fullLineSelection); 227 } 228 229 /* 230 * (non-Javadoc) 231 * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento) 232 */ 233 public void init(IViewSite site, IMemento memento) throws PartInitException { 234 super.init(site, memento); 235 this.viewState = memento; 236 } 237 238 /* 239 * Make the actions of the view: 240 * - change table line selection display 241 * - filter nightly builds 242 * - filter non-milestone builds 243 * - filter non-fingerprint scenarios 244 */ 245 void makeActions() { 246 247 // Full line selection action 248 this.fullLineSelection = new Action("", IAction.AS_CHECK_BOX) { 249 public void run() { 250 resetTabFolders(false/*refresh*/); 251 } 252 }; 253 this.fullLineSelection.setImageDescriptor(this.fullSelectionImageDescriptor); 254 this.fullLineSelection.setToolTipText("Full line selection"); 255 // this.fullLineSelection.setChecked(true); 256 257 // Filter non-fingerprints action 258 this.filterAdvancedScenarios = new Action("Advanced &Scenarios", IAction.AS_CHECK_BOX) { 259 public void run() { 260 ComponentResultsView.this.preferences.putBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, isChecked()); 261 resetTabFolders(false/*refresh*/); 262 } 263 }; 264 this.filterAdvancedScenarios.setChecked(true); 265 this.filterAdvancedScenarios.setToolTipText("Filter advanced scenarios (i.e. not fingerprint ones)"); 266 267 // Filter non-important builds action 268 this.filterOldBuilds = new Action("&Old Builds", IAction.AS_CHECK_BOX) { 269 public void run() { 270 ComponentResultsView.this.preferences.putBoolean(IPerformancesConstants.PRE_FILTER_OLD_BUILDS, isChecked()); 271 resetTabFolders(false/*refresh*/); 272 } 273 }; 274 this.filterOldBuilds.setChecked(false); 275 this.filterOldBuilds.setToolTipText("Filter old builds (i.e. before last milestone) but keep all previous milestones)"); 276 277 // Filter nightly action 278 this.filterNightlyBuilds = new Action("&Nightly", IAction.AS_CHECK_BOX) { 279 public void run() { 280 ComponentResultsView.this.preferences.putBoolean(IPerformancesConstants.PRE_FILTER_NIGHTLY_BUILDS, isChecked()); 281 resetTabFolders(false/*refresh*/); 282 } 283 }; 284 this.filterNightlyBuilds.setToolTipText("Filter nightly builds"); 285 } 286 287 /* (non-Javadoc) 288 * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent) 289 */ 290 public void preferenceChange(PreferenceChangeEvent event) { 291 String propertyName = event.getKey(); 292 Object newValue = event.getNewValue(); 293 294 // Filter non-fingerprints change 295 if (propertyName.equals(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS)) { 296 boolean checked = newValue == null ? IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS : "true".equals(newValue); 297 this.filterAdvancedScenarios.setChecked(checked); 298 resetTabFolders(false/*refresh*/); 299 } 300 301 // Filter non-milestone change 302 if (propertyName.equals(IPerformancesConstants.PRE_FILTER_OLD_BUILDS)) { 303 boolean checked = newValue == null ? IPerformancesConstants.DEFAULT_FILTER_OLD_BUILDS : "true".equals(newValue); 304 this.filterOldBuilds.setChecked(checked); 305 resetTabFolders(false/*refresh*/); 306 } 307 308 // Filter nightly builds change 309 if (propertyName.equals(IPerformancesConstants.PRE_FILTER_NIGHTLY_BUILDS)) { 310 boolean checked = newValue == null ? IPerformancesConstants.DEFAULT_FILTER_NIGHTLY_BUILDS : "true".equals(newValue); 311 this.filterNightlyBuilds.setChecked(checked); 312 resetTabFolders(false/*refresh*/); 313 } 314 } 315 316 /* 317 * Reset the table tab folders by re-create all the pages. 318 * Selections are set onto the first found error if this is the first tab creation (typically on a component change event from the ComponentsView) 319 * or to the previous one if this is just a refresh. 320 */ 321 void resetTabFolders(boolean init) { 322 323 // Store current indexes 324 int tabIndex = this.tabFolder.getSelectionIndex(); 325 int lineIndex = tabIndex<0 ? -1 : this.tabs[tabIndex].table.getSelectionIndex(); 326 327 // Create tab folders 328 CTabItem[] tabItems = this.tabFolder.getItems(); 329 int length = tabItems.length; 330 if (length == 0) { 331 createTabs(); 332 } else { 333 for (int i=0; i<length; i++) { 334 tabItems[i].setControl(this.tabs [i].createTabFolderPage(this.componentResultsElement, this.tabFolder, this.fullLineSelection.isChecked())); 335 } 336 } 337 338 // Set the part name when possible 339 if (this.componentResultsElement != null) { 340 setPartName(); 341 } 342 343 // If this is the first display then look for the first error to set the selection on it 344 if (init) { 345 if (this.componentResultsElement != null) { 346 // If the component has 347 if (this.componentResultsElement.hasError()) { 348 ResultsElement[] children = this.componentResultsElement.getChildren(); // get scenarios 349 int childrenLength = children.length; 350 for (int s=0; s<childrenLength; s++) { 351 if (children[s].hasError()) { 352 children = children[s].getChildren(); // get configs 353 for (int c=0; c<childrenLength; c++) { 354 if (children[c].hasError()) { 355 tabIndex = c; 356 break; 357 } 358 } 359 break; 360 } 361 } 362 } 363 } 364 lineIndex = 0; 365 } 366 367 // Set the selection 368 if (tabIndex >= 0 && lineIndex >= 0) { 369 this.tabFolder.setSelection(tabIndex); 370 Table table = this.tabs[tabIndex].table; 371 table.setSelection(lineIndex); 372 } 373 } 374 375 /* 376 * Restore the view state from the memento information. 377 */ 378 void restoreState() { 379 380 // Filter baselines action state 381 if (this.viewState != null) { 382 Boolean state = this.viewState.getBoolean(IPerformancesConstants.PRE_FULL_LINE_SELECTION); 383 boolean fullLine = state == null ? true : state.booleanValue(); 384 this.fullLineSelection.setChecked(fullLine); 385 } 386 387 // Filter non fingerprints action state 388 boolean checked = this.preferences.getBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS); 389 this.filterAdvancedScenarios.setChecked(checked); 390 391 // Filter nightly builds action 392 checked = this.preferences.getBoolean(IPerformancesConstants.PRE_FILTER_NIGHTLY_BUILDS, IPerformancesConstants.DEFAULT_FILTER_NIGHTLY_BUILDS); 393 this.filterNightlyBuilds.setChecked(checked); 394 395 // Filter non important builds action state 396 checked = this.preferences.getBoolean(IPerformancesConstants.PRE_FILTER_OLD_BUILDS, IPerformancesConstants.DEFAULT_FILTER_OLD_BUILDS); 397 this.filterOldBuilds.setChecked(checked); 398 } 399 400 /* 401 * (non-Javadoc) 402 * @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento) 403 */ 404 public void saveState(IMemento memento) { 405 super.saveState(memento); 406 memento.putBoolean(IPerformancesConstants.PRE_FULL_LINE_SELECTION, this.fullLineSelection.isChecked()); 407 } 408 409 /* 410 * (non-Javadoc) 411 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) 412 */ 413 public void selectionChanged(SelectionChangedEvent event) { 414 ResultsElement selectedElement = (ResultsElement) ((TreeSelection) event.getSelection()).getFirstElement(); 415 ComponentResultsElement componentElement = null; 416 ScenarioResultsElement scenarioResultsElement = null; 417 ConfigResultsElement configResultsElement = null; 418 BuildResultsElement buildResultsElement = null; 419 if (selectedElement instanceof ComponentResultsElement) { 420 componentElement = (ComponentResultsElement) selectedElement; 421 } else if (selectedElement instanceof ScenarioResultsElement) { 422 scenarioResultsElement = (ScenarioResultsElement) selectedElement; 423 componentElement = (ComponentResultsElement) scenarioResultsElement.getParent(null); 424 } else if (selectedElement instanceof ConfigResultsElement) { 425 configResultsElement = (ConfigResultsElement) selectedElement; 426 scenarioResultsElement = (ScenarioResultsElement) configResultsElement.getParent(null); 427 componentElement = (ComponentResultsElement) scenarioResultsElement.getParent(null); 428 } else if (selectedElement instanceof BuildResultsElement) { 429 buildResultsElement = (BuildResultsElement) selectedElement; 430 configResultsElement = (ConfigResultsElement) buildResultsElement.getParent(null); 431 scenarioResultsElement = (ScenarioResultsElement) configResultsElement.getParent(null); 432 componentElement = (ComponentResultsElement) scenarioResultsElement.getParent(null); 433 } else if (selectedElement instanceof DimResultsElement) { 434 buildResultsElement = (BuildResultsElement) selectedElement.getParent(null); 435 configResultsElement = (ConfigResultsElement) buildResultsElement.getParent(null); 436 scenarioResultsElement = (ScenarioResultsElement) configResultsElement.getParent(null); 437 componentElement = (ComponentResultsElement) scenarioResultsElement.getParent(null); 438 } 439 if (componentElement != this.componentResultsElement) { 440 this.componentResultsElement = componentElement; 441 if (componentElement == null || this.componentResultsElement.getChildren(null).length > 0) { 442 resetTabFolders(true); 443 } 444 } 445 if (configResultsElement != null) { 446 ConfigTab configTab = this.tabs[this.tabFolder.getSelectionIndex()]; 447 if (!configResultsElement.getName().equals(configTab.configName)) { 448 int length = this.tabs.length; 449 for (int i=0; i<length; i++) { 450 if (this.tabs[i].configName.equals(configResultsElement.getName())) { 451 this.tabFolder.setSelection(i); 452 } 453 } 454 } 455 if (buildResultsElement != null) { 456 configTab = this.tabs[this.tabFolder.getSelectionIndex()]; 457 configTab.select(buildResultsElement); 458 } 459 } 460 } 461 462 /* 463 * (non-Javadoc) 464 * @see org.eclipse.ui.part.WorkbenchPart#setFocus() 465 */ 466 public void setFocus() { 467 // do nothing 468 } 469 470 /* 471 * Set the name of the part. 472 * This name is built from the name of the component selected in the Components view. 473 * The rules to build the name are: 474 * 1. If the component name does not start then the part name is just "'<component name>' results" 475 * 2. Otherwise, remove "org.eclipse." form the component name and count the tokens separated by a dot ('.') 476 * a. if there's only one remaining token, then the part name is "Platform/" 477 * + "<token uppercased>" if token is less than 3 characters,"<token with first char uppercased>" otherwise 478 * b. otherwise then the part name is "<first token uppercased>" 479 * + for each followed additional token: 480 * "<token uppercased>" if token is less than 3 characters,"<token with first char uppercased>" otherwise 481 * + " results" 482 * E.g. 483 * - org.eclipse.ui -> "Platform/UI" 484 * - org.eclipse.swt -> "Platform/SWT" 485 * - org.eclipse.team -> "Platform/Team" 486 * - org.eclipse.jdt.ui -> "JDT/UI" 487 * - org.eclipse.jdt.core -> "JDT/Core" 488 * - org.eclipse.pde.api.tools -> "PDE/API Tools" 489 */ 490 protected void setPartName() { 491 String componentName = this.componentResultsElement.getName(); 492 String partName; 493 StringBuffer buffer = null; 494 if (componentName.startsWith(ORG_ECLIPSE)) { 495 partName = componentName.substring(ORG_ECLIPSE.length()); 496 StringTokenizer tokenizer = new StringTokenizer(partName, "."); 497 while (tokenizer.hasMoreTokens()) { 498 String token = tokenizer.nextToken(); 499 if (buffer == null) { 500 if (tokenizer.hasMoreTokens()) { 501 buffer = new StringBuffer("'"+token.toUpperCase()); 502 buffer.append('/'); 503 } else { 504 buffer = new StringBuffer("'Platform/"); 505 if (token.length() > 3) { 506 buffer.append(Character.toUpperCase(token.charAt(0))); 507 buffer.append(token.substring(1)); 508 } else { 509 buffer.append(token.toUpperCase()); 510 } 511 } 512 } else { 513 if (token.length() > 3) { 514 buffer.append(Character.toUpperCase(token.charAt(0))); 515 buffer.append(token.substring(1)); 516 } else { 517 buffer.append(token.toUpperCase()); 518 } 519 if (tokenizer.hasMoreTokens()) buffer.append(' '); 520 } 521 } 522 } else { 523 buffer = new StringBuffer("'"); 524 buffer.append(componentName); 525 buffer.append("'"); 526 } 527 buffer.append("' results"); 528 setPartName(buffer.toString()); 529 } 530 531 } 532