Home | History | Annotate | Download | only in ui
      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