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.io.BufferedOutputStream;
     14 import java.io.DataOutputStream;
     15 import java.io.File;
     16 import java.io.FileNotFoundException;
     17 import java.io.FileOutputStream;
     18 import java.io.IOException;
     19 import java.util.HashSet;
     20 import java.util.Iterator;
     21 import java.util.Set;
     22 
     23 import org.eclipse.core.runtime.preferences.InstanceScope;
     24 import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
     25 import org.eclipse.jface.action.Action;
     26 import org.eclipse.jface.action.IAction;
     27 import org.eclipse.jface.action.IMenuManager;
     28 import org.eclipse.jface.action.Separator;
     29 import org.eclipse.jface.dialogs.MessageDialog;
     30 import org.eclipse.jface.resource.JFaceResources;
     31 import org.eclipse.jface.viewers.AbstractTreeViewer;
     32 import org.eclipse.jface.viewers.ISelectionChangedListener;
     33 import org.eclipse.jface.viewers.SelectionChangedEvent;
     34 import org.eclipse.jface.viewers.StructuredSelection;
     35 import org.eclipse.jface.viewers.TreeViewer;
     36 import org.eclipse.jface.viewers.Viewer;
     37 import org.eclipse.jface.viewers.ViewerFilter;
     38 import org.eclipse.jface.viewers.ViewerSorter;
     39 import org.eclipse.swt.SWT;
     40 import org.eclipse.swt.graphics.Font;
     41 import org.eclipse.swt.graphics.FontData;
     42 import org.eclipse.swt.widgets.Composite;
     43 import org.eclipse.swt.widgets.Display;
     44 import org.eclipse.test.internal.performance.results.model.BuildResultsElement;
     45 import org.eclipse.test.internal.performance.results.model.ComponentResultsElement;
     46 import org.eclipse.test.internal.performance.results.model.ConfigResultsElement;
     47 import org.eclipse.test.internal.performance.results.model.ResultsElement;
     48 import org.eclipse.test.internal.performance.results.model.ScenarioResultsElement;
     49 import org.eclipse.test.internal.performance.results.utils.IPerformancesConstants;
     50 import org.eclipse.test.internal.performance.results.utils.Util;
     51 import org.eclipse.ui.IMemento;
     52 import org.eclipse.ui.PlatformUI;
     53 import org.eclipse.ui.model.WorkbenchContentProvider;
     54 import org.eclipse.ui.model.WorkbenchLabelProvider;
     55 
     56 /**
     57  * View to see the performance results of all the components in a hierarchical tree.
     58  * <p>
     59  * A component defines several performance scenarios which are run on several
     60  * machines (aka config). All builds results are stored onto each configuration
     61  * and 2 dimensions have been stored for each result: the "Elapsed Process Time"
     62  * and the "CPU Time".
     63  * </p><p>
     64  * There's only one available action from this view: read the local data files. This
     65  * populates the hierarchy with the numbers stored in these files.
     66  * </p><p>
     67  * There's also the possibility to filter the results:
     68  * 	<ul>
     69  *	<li>Filter for builds:
     70  *		<ul>
     71  *		<li>Filter baselines:	hide the baselines (starting with R-3.x)</li>
     72  *		<li>Filter nightly:	hide the nightly builds (starting with 'N')</li>
     73  *		<li>Filter non-important builds:	hide all non-important builds, which means non-milestone builds and those after the last milestone</li>
     74  *		</ul>
     75  *	</li>
     76  *	</li>Filter for scenarios:
     77  *		<ul>
     78  *		<li>Filter non-fingerprints: hide the scenarios which are not in the fingerprints</li>
     79  *		</ul>
     80  *	</li>
     81  *	</ul>
     82  * </p>
     83  * @see ComponentResultsView
     84  */
     85 public class ComponentsView extends PerformancesView {
     86 
     87 	// Viewer filters
     88 	final static ViewerFilter FILTER_ADVANCED_SCENARIOS = new ViewerFilter() {
     89 		public boolean select(Viewer v, Object parentElement, Object element) {
     90 			if (element instanceof ScenarioResultsElement) {
     91 				ScenarioResultsElement scenarioElement = (ScenarioResultsElement) element;
     92 				return scenarioElement.hasSummary();
     93 			}
     94 	        return true;
     95         }
     96 	};
     97 
     98 	// Views
     99 	PerformancesView buildsView;
    100 	ComponentResultsView componentResultsView = null;
    101 
    102 	// Internal
    103 	Set expandedComponents = new HashSet();
    104 	File resultsDir = null;
    105 
    106 	// Actions
    107 	Action filterAdvancedScenarios;
    108 	Action writeStatus;
    109 
    110 	// SWT resources
    111 	Font boldFont;
    112 
    113 	// Write Status
    114 	static int WRITE_STATUS;
    115 
    116 /**
    117  * Default constructor.
    118  */
    119 public ComponentsView() {
    120 //	this.onlyFingerprintsImageDescriptor = ImageDescriptor.createFromFile(getClass(), "filter_ps.gif");
    121 	super();
    122 
    123 	// Get preferences
    124 	this.preferences = new InstanceScope().getNode(IPerformancesConstants.PLUGIN_ID);
    125 
    126 	// Init status
    127 	WRITE_STATUS = this.preferences.getInt(IPerformancesConstants.PRE_WRITE_STATUS, IPerformancesConstants.DEFAULT_WRITE_STATUS);
    128 
    129 }
    130 
    131 /*
    132  * (non-Javadoc)
    133  * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#createPartControl(org.eclipse.swt.widgets.Composite)
    134  */
    135 public void createPartControl(Composite parent) {
    136 	super.createPartControl(parent);
    137 
    138 	// Create the viewer
    139 	this.viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
    140 
    141 	// Set the content provider: first level is components list
    142 	WorkbenchContentProvider contentProvider = new WorkbenchContentProvider() {
    143 		public Object[] getElements(Object o) {
    144 			return ComponentsView.this.getElements();
    145 		}
    146 	};
    147 	this.viewer.setContentProvider(contentProvider);
    148 
    149 	// Set the label provider
    150 	WorkbenchLabelProvider labelProvider = new WorkbenchLabelProvider() {
    151 
    152 		protected String decorateText(String input, Object element) {
    153 			String text = super.decorateText(input, element);
    154 			if (element instanceof BuildResultsElement) {
    155 				BuildResultsElement buildElement = (BuildResultsElement) element;
    156 				if (buildElement.isMilestone()) {
    157 					text = Util.getMilestoneName(buildElement.getName()) + " - "+text;
    158 				}
    159 			}
    160 			return text;
    161 		}
    162 
    163 		// When all scenarios are displayed, then set fingerprints one in bold.
    164 		public Font getFont(Object element) {
    165 			Font font = super.getFont(element);
    166 			if (element instanceof ScenarioResultsElement) {
    167 //				Action fingerprints = ComponentsView.this.filterNonFingerprints;
    168 //				if (fingerprints != null && !fingerprints.isChecked()) {
    169 				boolean fingerprints = ComponentsView.this.preferences.getBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS);
    170 				if (!fingerprints) {
    171 					ScenarioResultsElement scenarioElement = (ScenarioResultsElement) element;
    172 					if (scenarioElement.hasSummary()) {
    173 						return getBoldFont(font);
    174 					}
    175 				}
    176 			}
    177 			if (element instanceof BuildResultsElement) {
    178 				BuildResultsElement buildElement = (BuildResultsElement) element;
    179 				if (Util.isMilestone(buildElement.getName())) {
    180 					return getBoldFont(font);
    181 				}
    182 			}
    183 			return font;
    184 		}
    185 	};
    186 	this.viewer.setLabelProvider(labelProvider);
    187 
    188 	// Set the children sorter
    189 	ViewerSorter nameSorter = new ViewerSorter() {
    190 
    191 		// Sort children using specific comparison (see the implementation
    192 		// of the #compareTo(Object) in the ResultsElement hierarchy
    193 		public int compare(Viewer view, Object e1, Object e2) {
    194 			// Config and Build results are sorted in reverse order
    195 			if (e1 instanceof BuildResultsElement) {
    196 				ResultsElement element = (ResultsElement) e2;
    197 				return element.compareTo(e1);
    198 			}
    199 			if (e1 instanceof ResultsElement) {
    200 				ResultsElement element = (ResultsElement) e1;
    201 				return element.compareTo(e2);
    202 			}
    203 			return super.compare(view, e1, e2);
    204 		}
    205 	};
    206 	this.viewer.setSorter(nameSorter);
    207 
    208 	// Add results view as listener to viewer selection changes
    209 	Display.getDefault().asyncExec(new Runnable() {
    210 		public void run() {
    211 			ISelectionChangedListener listener = getResultsView();
    212 			if (listener != null) {
    213 				ComponentsView.this.viewer.addSelectionChangedListener(listener);
    214 			}
    215 		}
    216 	});
    217 
    218 	// Finalize viewer initialization
    219 	PlatformUI.getWorkbench().getHelpSystem().setHelp(this.viewer.getControl(), "org.eclipse.test.performance.ui.components");
    220 	finalizeViewerCreation();
    221 }
    222 
    223 /*
    224  * (non-Javadoc)
    225  * @see org.eclipse.ui.part.WorkbenchPart#dispose()
    226  */
    227 public void dispose() {
    228 	if (this.boldFont != null) {
    229 		this.boldFont.dispose();
    230 	}
    231 //	JFaceResources.getResources().destroyImage(this.onlyFingerprintsImageDescriptor);
    232 	super.dispose();
    233 }
    234 
    235 /*
    236  * (non-Javadoc)
    237  * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#fillLocalPullDown(org.eclipse.jface.action.IMenuManager)
    238  */
    239 void fillFiltersDropDown(IMenuManager manager) {
    240 	super.fillFiltersDropDown(manager);
    241 	manager.add(this.filterOldBuilds);
    242 	manager.add(this.filterLastBuilds);
    243 	manager.add(new Separator());
    244 	manager.add(this.filterAdvancedScenarios);
    245 }
    246 
    247 void fillLocalPullDown(IMenuManager manager) {
    248 	super.fillLocalPullDown(manager);
    249 	manager.add(new Separator());
    250 	manager.add(this.writeStatus);
    251 }
    252 
    253 /*
    254  * Filter non fingerprints scenarios action run.
    255  */
    256 void filterAdvancedScenarios(boolean fingerprints, boolean updatePreference) {
    257 	this.results.setFingerprints(fingerprints);
    258 	if (fingerprints) {
    259 		this.viewFilters.add(FILTER_ADVANCED_SCENARIOS);
    260 	} else {
    261 		this.viewFilters.remove(FILTER_ADVANCED_SCENARIOS);
    262 	}
    263 	this.preferences.putBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, fingerprints);
    264 	updateFilters();
    265 }
    266 
    267 /*
    268  * Returns the bold font.
    269  */
    270 Font getBoldFont(Font font) {
    271 	if (this.boldFont == null) {
    272 		FontData[] fontData = (font==null ? JFaceResources.getDefaultFont() : font).getFontData();
    273 		FontData boldFontData = new FontData(fontData[0].getName(), fontData[0].getHeight(), SWT.BOLD);
    274 		this.boldFont = new Font(this.display, boldFontData);
    275 	}
    276 	return this.boldFont;
    277 }
    278 
    279 /*
    280  * Get all the components from the model.
    281  */
    282 Object[] getElements() {
    283 	if (this.results == null) {
    284 		initResults();
    285 		if (this.filterAdvancedScenarios != null) {
    286 			this.results.setFingerprints(this.filterAdvancedScenarios.isChecked());
    287 		}
    288 	}
    289 	return this.results.getElements();
    290 }
    291 
    292 /*
    293  * Return the components results view.
    294  */
    295 ComponentResultsView getResultsView() {
    296 	if (this.componentResultsView == null) {
    297 		this.componentResultsView = (ComponentResultsView) getWorkbenchView("org.eclipse.test.internal.performance.results.ui.ComponentsResultsView");
    298 	}
    299 	return this.componentResultsView;
    300 }
    301 
    302 /*
    303  * Return the builds view.
    304  */
    305 PerformancesView getSiblingView() {
    306 	if (this.buildsView == null) {
    307 		this.buildsView = (PerformancesView) getWorkbenchView("org.eclipse.test.internal.performance.results.ui.BuildsView");
    308 	}
    309 	return this.buildsView;
    310 }
    311 
    312 /*
    313  * (non-Javadoc)
    314  * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#makeActions()
    315  */
    316 void makeActions() {
    317 
    318 	super.makeActions();
    319 
    320 	// Filter non-fingerprints action
    321 	this.filterAdvancedScenarios = new Action("Advanced &Scenarios", IAction.AS_CHECK_BOX) {
    322 		public void run() {
    323 			filterAdvancedScenarios(isChecked(), true/*update preference*/);
    324         }
    325 	};
    326 	this.filterAdvancedScenarios.setChecked(true);
    327 	this.filterAdvancedScenarios.setToolTipText("Filter advanced scenarios (i.e. not fingerprint ones)");
    328 
    329 	// Write status
    330 	this.writeStatus = new Action("Write status") {
    331 		public void run() {
    332 
    333 			// Get write directory
    334 			String filter = (ComponentsView.this.resultsDir == null) ? null : ComponentsView.this.resultsDir.getPath();
    335 			final File writeDir = changeDir(filter, "Select a directory to write the status");
    336 			if (writeDir != null) {
    337 				writeStatus(writeDir);
    338 			}
    339         }
    340 	};
    341 	this.writeStatus.setEnabled(true);
    342 	this.writeStatus.setToolTipText("Write component status to a file");
    343 
    344 	// Set filters default
    345 	this.filterBaselineBuilds.setChecked(true);
    346 	this.filterNightlyBuilds.setChecked(false);
    347 }
    348 
    349 /* (non-Javadoc)
    350  * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent)
    351  */
    352 public void preferenceChange(PreferenceChangeEvent event) {
    353 	String propertyName = event.getKey();
    354 	Object newValue = event.getNewValue();
    355 
    356 	// Filter non-fingerprints change
    357 	if (propertyName.equals(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS)) {
    358 		boolean checked = newValue == null ? IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS : "true".equals(newValue);
    359 		filterAdvancedScenarios(checked, false/*do not update preference*/);
    360 		this.filterAdvancedScenarios.setChecked(checked);
    361 	}
    362 
    363 	// Filter non-milestone change
    364 	if (propertyName.equals(IPerformancesConstants.PRE_FILTER_OLD_BUILDS)) {
    365 		boolean checked = newValue == null ? IPerformancesConstants.DEFAULT_FILTER_OLD_BUILDS : "true".equals(newValue);
    366 		filterOldBuilds(checked, false/*do not update preference*/);
    367 		this.filterOldBuilds.setChecked(checked);
    368 	}
    369 
    370 	// Write status
    371 	if (propertyName.equals(IPerformancesConstants.PRE_WRITE_STATUS)) {
    372 		WRITE_STATUS = newValue == null ? IPerformancesConstants.DEFAULT_WRITE_STATUS : Integer.parseInt((String)newValue);
    373 	}
    374 
    375 	super.preferenceChange(event);
    376 }
    377 
    378 void restoreState() {
    379 	super.restoreState();
    380 
    381 	// Filter baselines action default
    382 	if (this.viewState == null) {
    383 		this.filterBaselineBuilds.setChecked(true);
    384 		this.viewFilters.add(FILTER_BASELINE_BUILDS);
    385 	} else {
    386 		String dir = this.viewState.getString(IPerformancesConstants.PRE_WRITE_RESULTS_DIR);
    387 		if (dir != null) {
    388 			this.resultsDir = new File(dir);
    389 		}
    390 	}
    391 
    392 	// Filter non fingerprints action state
    393 	boolean checked = this.preferences.getBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS);
    394 	this.filterAdvancedScenarios.setChecked(checked);
    395 	if (checked) {
    396 		this.viewFilters.add(FILTER_ADVANCED_SCENARIOS);
    397 	}
    398 }
    399 
    400 public void saveState(IMemento memento) {
    401 	if (this.resultsDir != null) {
    402 		memento.putString(IPerformancesConstants.PRE_WRITE_RESULTS_DIR, this.resultsDir.getPath());
    403 	}
    404 	super.saveState(memento);
    405 }
    406 
    407 /**
    408  * Select a results element in the tree.
    409  */
    410 public void select(ComponentResultsElement componentResults, String configName, String scenarioName, String buildName) {
    411 
    412 	// Collapse previous expanded components except the requested one
    413 	// TODO (frederic) also collapse expanded components children elements
    414 	this.expandedComponents.remove(componentResults);
    415 	Iterator iterator = this.expandedComponents.iterator();
    416 	while (iterator.hasNext()) {
    417 		this.viewer.collapseToLevel(iterator.next(), AbstractTreeViewer.ALL_LEVELS);
    418 	}
    419 	this.expandedComponents.clear();
    420 
    421 	// Set the tree selection
    422 	ScenarioResultsElement scenarioResultsElement = (ScenarioResultsElement) componentResults.getResultsElement(scenarioName);
    423 	if (scenarioResultsElement != null) {
    424 		ConfigResultsElement configResultsElement = (ConfigResultsElement) scenarioResultsElement.getResultsElement(configName);
    425 		if (configResultsElement != null) {
    426 			BuildResultsElement buildResultsElement = (BuildResultsElement) configResultsElement.getResultsElement(buildName);
    427 			if (buildResultsElement != null) {
    428 				this.viewer.setSelection(new StructuredSelection(buildResultsElement), true);
    429 				this.setFocus();
    430 			}
    431 		}
    432 	}
    433 }
    434 
    435 /*
    436  * (non-Javadoc)
    437  * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
    438  */
    439 public void selectionChanged(SelectionChangedEvent event) {
    440 	super.selectionChanged(event);
    441 	ResultsElement eventResultsElement = (ResultsElement) ((StructuredSelection)event.getSelection()).getFirstElement();
    442 	if (eventResultsElement != null) {
    443 		ResultsElement eventComponentElement = eventResultsElement;
    444 		if (!(eventComponentElement instanceof ComponentResultsElement)) {
    445 			while (!(eventComponentElement instanceof ComponentResultsElement)) {
    446 				eventComponentElement = (ResultsElement) eventComponentElement.getParent(null);
    447 			}
    448 			this.expandedComponents.add(eventComponentElement);
    449 		}
    450 	}
    451 }
    452 
    453 protected void writeStatus(File writeDir) {
    454 		this.resultsDir = writeDir;
    455 		if (this.filterAdvancedScenarios.isChecked()) {
    456 			writeDir = new File(writeDir, "fingerprints");
    457 		} else {
    458 			writeDir = new File(writeDir, "all");
    459 		}
    460 		writeDir.mkdir();
    461 		if ((WRITE_STATUS & IPerformancesConstants.STATUS_VALUES) != 0) {
    462 			writeDir = new File(writeDir, "values");
    463 		}
    464 		int buildsNumber = WRITE_STATUS & IPerformancesConstants.STATUS_BUILDS_NUMBER_MASK;
    465 		if (buildsNumber > 1) {
    466 			writeDir = new File(writeDir, Integer.toString(buildsNumber));
    467 		}
    468 		writeDir.mkdirs();
    469 		String prefix = this.results.getName();
    470 		File resultsFile = new File(writeDir, prefix+".log");
    471 		File exclusionDir = new File(writeDir, "excluded");
    472 		exclusionDir.mkdir();
    473 		File exclusionFile = new File(exclusionDir, prefix+".log");
    474 		if (resultsFile.exists()) {
    475 			int i=0;
    476 			File saveDir = new File(writeDir, "save");
    477 			saveDir.mkdir();
    478 			while (true) {
    479 				String newFileName = prefix+"_";
    480 				if (i<10) newFileName += "0";
    481 				newFileName += i;
    482 				File renamedFile = new File(saveDir, newFileName+".log");
    483 				if (resultsFile.renameTo(renamedFile)) {
    484 					File renamedExclusionFile = new File(exclusionDir, newFileName+".log");
    485 					exclusionFile.renameTo(renamedExclusionFile);
    486 					break;
    487 				}
    488 				i++;
    489 			}
    490 		}
    491 
    492 		// Write status
    493 		StringBuffer excluded = this.results.writeStatus(resultsFile, WRITE_STATUS);
    494 		if (excluded == null) {
    495 			MessageDialog.openWarning(this.shell, getTitleToolTip(), "The component is not read, hence no results can be written!");
    496 		}
    497 
    498 		// Write exclusion file
    499 		try {
    500 			DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(exclusionFile)));
    501 			try {
    502 				stream.write(excluded.toString().getBytes());
    503 			}
    504 			finally {
    505 				stream.close();
    506 			}
    507 		} catch (FileNotFoundException e) {
    508 			System.err.println("Can't create exclusion file"+exclusionFile); //$NON-NLS-1$
    509 		} catch (IOException e) {
    510 			e.printStackTrace();
    511 		}
    512 }
    513 }