sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/ui/MainView.java
/*
* Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Definitions for the class MainView
*
*/
package com.nokia.s60tools.analyzetool.ui;
import java.io.FileInputStream;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Locale;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeExpansionEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.navigator.CommonNavigator;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.views.navigator.ResourceNavigator;
import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
import com.nokia.carbide.cpp.internal.project.ui.views.SymbianProjectNavigatorView;
import com.nokia.s60tools.analyzetool.Activator;
import com.nokia.s60tools.analyzetool.AnalyzeToolHelpContextIDs;
import com.nokia.s60tools.analyzetool.builder.BuilderUtil;
import com.nokia.s60tools.analyzetool.engine.AnalysisItem;
import com.nokia.s60tools.analyzetool.engine.AnalyzeFactory;
import com.nokia.s60tools.analyzetool.engine.CallstackItem;
import com.nokia.s60tools.analyzetool.engine.DeferredCallstackManager;
import com.nokia.s60tools.analyzetool.engine.EpocReader;
import com.nokia.s60tools.analyzetool.engine.IMemoryActivityModel;
import com.nokia.s60tools.analyzetool.engine.MMPInfo;
import com.nokia.s60tools.analyzetool.engine.ParseAnalyzeData;
import com.nokia.s60tools.analyzetool.engine.ParseXMLFileSAX;
import com.nokia.s60tools.analyzetool.engine.ProjectResults;
import com.nokia.s60tools.analyzetool.engine.RunResults;
import com.nokia.s60tools.analyzetool.engine.SimpleCallstackManager;
import com.nokia.s60tools.analyzetool.engine.UseAtool;
import com.nokia.s60tools.analyzetool.engine.statistic.ProcessInfo;
import com.nokia.s60tools.analyzetool.engine.statistic.ReadFile;
import com.nokia.s60tools.analyzetool.global.Constants;
import com.nokia.s60tools.analyzetool.global.Util;
import com.nokia.s60tools.analyzetool.internal.ui.graph.ChartContainer;
import com.nokia.s60tools.analyzetool.ui.actions.DropDownMenu;
import com.nokia.s60tools.analyzetool.ui.actions.FileActionHistory;
import com.nokia.s60tools.analyzetool.ui.statistic.StatisticView;
/**
* AnalyzeTool main view which displays memory analysis results and provides
* interface for all the functionalities what AnalyzeTool has.
*
* @author kihe
*
*/
public class MainView extends ViewPart implements ISelectionListener,
ITreeViewerListener, IActionListener, ISelectionChangedListener,
KeyListener {
/**
* Sorts tree view objects.
*
* @author kihe
*/
public static class NameSorter extends ViewerSorter {
/**
* Compares view items.
*
* @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer,
* java.lang.Object, java.lang.Object)
*
* @param viewer
* Viewer
* @param e1
* Object
* @param e2
* Object
* @return int Always return 0
*/
@Override
public int compare(final Viewer viewer, final Object e1, final Object e2) {
return 0;
}
}
/**
* The content provider class is responsible for providing objects to the
* view. It can wrap existing objects in adapters or simply return objects
* as-is. These objects may be sensitive to the current input of the view,
* or ignore it and always show the same content (like Task List, for
* example).
*/
class ViewContentProvider implements ITreeContentProvider {
/**
*
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
// MethodDeclaration/Block[count(BlockStatement) = 0 and
// @containsComment = 'false']
}
/**
*
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(Object parent) {
if (parent instanceof TreeParent) {
return ((TreeParent) parent).getChildren();
}
return new Object[0];
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.IStructuredContentProvider#getElements(
* java.lang.Object)
*/
public Object[] getElements(Object parent) {
if (parent.equals(getViewSite())) {
if (invisibleRoot == null) {
getStartupContent();
}
return getChildren(invisibleRoot);
}
return getChildren(parent);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang
* .Object)
*/
public Object getParent(Object child) {
if (child instanceof TreeObject) {
return ((TreeObject) child).getParent();
}
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang
* .Object)
*/
public boolean hasChildren(Object parent) {
if (parent instanceof TreeParent) {
return ((TreeParent) parent).hasChildren();
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse
* .jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
// MethodDeclaration/Block[count(BlockStatement) = 0 and
// @containsComment = 'false']
}
}
/**
* Provides elements of tree view.
*
* @author kihe
*
*/
public class ViewLabelProvider extends LabelProvider {
/**
* Used when tree model item is TreeParent.
*/
private final Image folder;
/**
* Default element only used to show error situations.
*/
private final Image element;
/**
* Used when tree model item is part of the module which is build with
* AnalyzeTool.
*/
private final Image build;
/**
* Used when tree model item is part of the project but not build with
* with AnalyzeTool.
*/
private final Image notBuild;
/**
* Used when tree model item is outside of the project modules.
*/
public Image outside;
/**
* Constructor. Created all the images which is used in the AnalyzeTool
* tree model.
*/
public ViewLabelProvider() {
// create images
folder = PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJ_FOLDER);
element = PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJ_ELEMENT);
build = Activator.getImageDescriptor(Constants.ICON_BUILD)
.createImage();
notBuild = Activator.getImageDescriptor(Constants.ICON_NOT_BUILD)
.createImage();
outside = Activator.getImageDescriptor(Constants.ICON_OUTSIDE)
.createImage();
}
/**
* Gets current tree object image.
*
* @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
*
* @param obj
* Current tree model item
* @return Corresponding image of tree view object
*/
@Override
public Image getImage(final Object obj) {
// if object is TreeParent return "folder" icon
if (obj instanceof TreeParent) {
return folder;
}
// if object is TreeObject, need to change icon to match object
// state
else if (obj instanceof TreeObject) {
// get TreeObject
TreeObject tempObject = (TreeObject) obj;
// change object icon if module belongs to selected project
if (tempObject.isBelongs()) {
// if module is built with AnalyzeTool
if (tempObject.isBuild()) {
return build;
}
// module not build with AnalyzeTool
return notBuild;
}
// module not belong to selected project
return outside;
}
return element;
}
/**
* Gets current tree view object name.
*
* @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
*
* @return Current tree view object name
*/
@Override
public final String getText(final Object obj) {
return obj.toString();
}
}
/** Is trace actions enabled. */
public static boolean enableTrace;
/** Title of the AnalyzeTool view */
private String viewTitle = Constants.ANALYZE_TOOL_TITLE;
/** Line feed character. */
private static String lineFeed = "\n";
/** Contains information of test runs. */
public TreeViewer runView;
/** Contains one memory leak call stack addresses. */
private TreeViewer callstackView;
/** Tree parent object which not shown to user. */
private TreeParent invisibleRoot;
/** Double click action. */
private Action doubleClickAction;
/** Click action. */
private Action clickAction;
/** Change detail level action. */
public Action changeDetails;
/** Select S60 log file action. */
private Action s60LogTargetAction;
/** Select TraceViewer connection action. */
// private Action externalLogTargetAction;
/** Select fast data gathering mode */
private Action externalFastLogTargetAction;
/** Select Ask always action. */
private Action askLogTargetAction;
/** Save report file action. */
private Action saveReportAction;
/** Save test run action. */
private Action saveDataFileAction;
/** AnalyzeTool results action. */
private Action analyzeResults;
/** Activate AnalyzeTool build action. */
public Action buildWithAtool;
/** Clean AnalyzeTool changes action. */
private Action cleanAtoolChanges;
/** Start/Stop trace action. */
public Action traceAction;
/** Start subtest action. */
private Action startSubtest;
/** Stop subtest action. */
private Action stopSubtest;
/** Refresh(re-creates) project results */
private Action refreshResults;
/** Copies selected memory leak item info to the clipboard. */
private Action copyAction;
/** Action to open AnalyzeTool preference page. */
private Action openPrefs;
/**
* Clears selected project results without removing temporary files
*/
private Action clearProjectResults;
/** Selected project reference. */
public IProject project;
/** Previously select project reference. */
public IProject lastProjectRef;
/** Project reference for active trace. */
private IProject traceStartedProjectRef;
/** Contains detailed information of selected run or memory leak. */
public Label informationLabel;
/** Memory analysis parser. */
public ParseAnalyzeData parser;
/** Used data file. */
public String usedDataFileName = null;
/** Is trace active. */
private boolean traceActive = false;
/** Last active memory leak tree item. */
private TreeObject activeTreeItem;
/** Contains workbench (all project) related cpp file info. */
private final AbstractList<String> cppFileNames;
/** Contains started subtest information. */
private final AbstractList<ActiveSubtests> startedSubtest;
/** Contains project related module results. */
private final ProjectResults projectResults;
/** Job for analyzing data files. */
private Job analyzeJob;
/** Job for reading the data files for the graph. */
private GraphLoadJob graphLoadJob;
/** Last selected tree item. */
private Object lastSelectedObject;
/** Contains information of which files were opened. */
public FileActionHistory fileOpenHistory;
/** File open drop down menu. */
private DropDownMenu fileOpenMenu;
/** Log target action drop down menu. */
private DropDownMenu logTargetMenu;
/** Save file drop down menu. */
private DropDownMenu saveFileMenu;
/** Tab item for the "Top allocation locations" tab */
CTabItem memoryTab;
/** Tab item for the memory results tab */
CTabItem mainTab;
/** StatisticView reference */
StatisticView statisticView;
/** Contains project related modules */
private final Hashtable<IProject, AbstractList<MMPInfo>> projectModules;
/** Reads epocwind.out file */
EpocReader listeningJob;
/** The chart view composite */
protected ChartContainer chart;
/**
* The constructor.
*/
public MainView() {
parser = new ParseAnalyzeData(true, false, true);
cppFileNames = new ArrayList<String>();
startedSubtest = new ArrayList<ActiveSubtests>();
projectResults = new ProjectResults();
fileOpenHistory = new FileActionHistory(Constants.HISTORY_LEVEL);
projectModules = new Hashtable<IProject, AbstractList<MMPInfo>>();
}
/**
* Activates AnalyzeTool custom build if it is not activated.
*/
public final void activateAnalysisBuild() {
// check project validity
if (checkProjectValidity()) {
// add AnalyzeTool custom builder natures to project build nature
BuilderUtil bUtil = new BuilderUtil();
if (bUtil.isNatureEnabled(project)) {
bUtil.disableNatures(project);
} else {
bUtil.enableNatures(project);
}
}
// update build state
updateBuildState(project);
}
/*
* (non-Javadoc)
*
* @see com.nokia.s60tools.analyzetool.ui.IActionListener#allModulesBuilt()
*/
public final void buildStateChanged(final IProject projRef) {
// check validity
if (!project.equals(projRef) || projectResults == null) {
return;
}
final String datafile = projectResults.getDataFileName(projRef);
// if trace is captured or data file is opened
if (datafile != null && runView != null) {
// need to check is data file available in the disk
FileInputStream fis = null;
try {
// get existing file stream
fis = new FileInputStream(datafile);
// if file is empty => do nothing
if (fis.available() == 0) {
return;
}
} catch (java.io.FileNotFoundException fnfe) {
fnfe.printStackTrace();
return;
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
return;
} finally { // finally close input stream
try {
if (fis != null) {
fis.close();
fis = null;
}
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
}
}
// data file is available
int dataFileType = UseAtool.checkFileType(datafile);
if (dataFileType == Constants.DATAFILE_INVALID
|| dataFileType == Constants.DATAFILE_XML
|| dataFileType == Constants.DATAFILE_EMPTY) {
return;
}
boolean reGenerate = Util
.openConfirmationDialog(Constants.BUILD_STATE_CHANGED);
if (reGenerate) {
// sync with UI thread
runView.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
analyzeDataFile(Constants.ANALYZE_USE_DATA_FILE,
datafile, false);
}
});
}
}
}
/**
* Opens file dialog and analyzing data file for given location.
*
* @param type
* Type to define is data file asked from the user or using the
* give data file
* @param existingDataFile
* Data file path
* @param showErrorInfo
* Flag to determinate that displaying error info or not
*/
public final void analyzeDataFile(final int type,
final String existingDataFile, final boolean showErrorInfo) {
// is project selected
if (!checkProjectValidity()) {
return;
}
// user selected file
final String selectedFile;
// ask for user data file
if (type == Constants.ANALYZE_ASK_FOR_USER) {
selectedFile = Util.openFileDialog(getSite().getShell(),
Constants.DIALOG_SELECT_DATA_FILE, project.getLocation()
.toOSString());
} else if (existingDataFile == null) {
selectedFile = parser.getDataFileName();
} else {
selectedFile = existingDataFile;
}
// if user select some file
if (selectedFile != null) {
// clear previous data
projectResults.clearProjectData(project);
activeTreeItem = null;
clearCallstackViewContent();
updateInformationLabel("");
runView.setInput(getStartupContent());
changeViewTitle(viewTitle);
AbstractList<MMPInfo> modules = Util
.loadProjectTargetsInfo(project);
projectModules.put(project, modules);
boolean xmlFile = Util.isFileXML(selectedFile);
// if file is XML file
// no need to analyze data file
// => just create results from XML file
if (xmlFile) {
Job analyzingXMLJob = new Job(Constants.ANALYZE_TOOL_TITLE) {
@Override
protected IStatus run(IProgressMonitor monitor) {
// update progress monitor state
monitor.beginTask(Constants.PROGRESSDIALOG_TITLE,
IProgressMonitor.UNKNOWN);
// Parse the data file
ParseXMLFileSAX dataFileParser = new ParseXMLFileSAX(
project, selectedFile, projectResults);
boolean ret = dataFileParser.parse();
// set used datafile name
usedDataFileName = selectedFile;
fileOpenHistory.setFileName(selectedFile);
// if parsing success
// display memory leak results
if (ret) {
// update project results
projectResults.setProjectModules(project,
projectModules.get(project), dataFileParser
.getModules());
} else {
fileOpenHistory.removeFileName(selectedFile);
if (showErrorInfo) {
showErrorMessage(Constants.INFO_FILE_INVALID);
}
}
updateChangeDetailState(project);
refreshView();
dataFileParser = null;
return new Status(IStatus.OK,
Constants.ANALYZE_CONSOLE_ID, IStatus.OK,
Constants.PROGRESSDIALOG_ANALYZE_COMPLETE, null);
}
};
analyzingXMLJob.setUser(true);
analyzingXMLJob.schedule();
} else {
try {
analyzeWithAtool(project, selectedFile, showErrorInfo);
} catch (Exception e) {
analyzeJob = null;
}
}
}
}
/**
* Analyzing memory analysis results using atool.exe.
*
* @param projectRef
* Project reference
* @param usedFile
* Data file which contains memory analyze data
* @param showErrorInfo
* Flag to determinate that displaying error info or not
*/
public final void analyzeWithAtool(final IProject projectRef,
final String usedFile, final boolean showErrorInfo) {
// check that no existing job running
if (analyzeJob == null
|| analyzeJob.getResult().getCode() == IStatus.CANCEL
|| analyzeJob.getResult().getCode() == IStatus.ERROR) {
analyzeJob = new Job(Constants.ANALYZE_TOOL_TITLE) {
@Override
protected IStatus run(IProgressMonitor monitor) {
// inform progress dialog that task execution starts
// this make progress dialog visible on the UI
monitor.beginTask(Constants.PROGRESSDIALOG_ATOOL,
IProgressMonitor.UNKNOWN);
fileOpenHistory.setFileName(usedFile);
// add2UserActionHistory( "File opened: " + usedFile );
// set used datafile name
usedDataFileName = usedFile;
if (chart != null) {
resetGraphView();// clear out the graph view
}
// create atool object and execute atool
UseAtool atool = new UseAtool();
// create XML file
Constants.COMMAND_LINE_ERROR_CODE errorCode = atool
.createXmlAndCleanDatFilesToCarbide(monitor,
projectRef, usedFile, "-a");
String xmlFileLocation = atool.getXmlFilePath();
String cleanDatFileLocation = atool.getCleanDatFilePath();
// if some error occurs display it to user.
if (errorCode != Constants.COMMAND_LINE_ERROR_CODE.OK) {
fileOpenHistory.removeFileName(usedFile);
Util.displayCommandLineError(errorCode);
}
// if XML file generation failed => info to the user
else if (xmlFileLocation == null) {
fileOpenHistory.removeFileName(usedFile);
if (showErrorInfo) {
showErrorMessage(Constants.INFO_FILE_INVALID);
}
} else {
// Parse the XML file
ParseXMLFileSAX dataFileParser = new ParseXMLFileSAX(
project, xmlFileLocation, projectResults);
boolean error = dataFileParser.parse();
if (showErrorInfo && !error) {
fileOpenHistory.removeFileName(usedFile);
showErrorMessage(Constants.INFO_FILE_INVALID);
}
projectResults.setProjectModules(project,
projectModules.get(project), dataFileParser
.getModules());
projectResults.setDataFileName(projectRef,
usedDataFileName);
// update display
refreshView();
}
updateChangeDetailState(projectRef);
if (!monitor.isCanceled()) {
// create the job for loading the graph model
// but only schedule it when the user gets to the graph
// tab
graphLoadJob = new GraphLoadJob(cleanDatFileLocation);
graphLoadJob.setUser(true);// set progress bar
graphLoadJob.setPriority(Job.LONG);
// run the following in UI thread, since widgets get
// accessed
PlatformUI.getWorkbench().getDisplay().syncExec(
new Runnable() {
public void run() {
if (((CTabFolder) chart.getParent())
.getSelection() != null
&& ((CTabFolder) chart
.getParent())
.getSelection()
.getControl() == chart) {
// chart tab is currently selected
// so we can run the load job
// straight away
graphLoadJob.schedule();
}
}
});
}
analyzeJob = null;
return new Status(IStatus.OK, Constants.ANALYZE_CONSOLE_ID,
IStatus.OK,
Constants.PROGRESSDIALOG_ANALYZE_COMPLETE, null);
}
};
if (graphLoadJob != null && graphLoadJob.getState() == Job.RUNNING) {
graphLoadJob.cancel();
}
graphLoadJob = null;
analyzeJob.setUser(true);
analyzeJob.setPriority(Job.LONG);
analyzeJob.schedule();
} else {
// if existing job is running display info to user
showMessage(Constants.INFO_ALLREADY_RUNNING);
}
}
/**
* Change report detail level.
*/
public final void changeDetailLevel() {
// sync with UI thread
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
public void run() {
// get preference store
IPreferenceStore store = Activator.getPreferences();
// get active report level
String reportLevel = store.getString(Constants.REPORT_LEVEL);
boolean updateMemLeakAlso = false;
// set new report level
if (Constants.REPORT_EVERY.equals(reportLevel)) {
store.setValue(Constants.REPORT_LEVEL,
Constants.REPORT_KNOWN);
updateMemLeakAlso = true;
} else if (Constants.REPORT_KNOWN.equals(reportLevel)) {
store.setValue(Constants.REPORT_LEVEL,
Constants.REPORT_TOPMOST);
} else if (Constants.REPORT_TOPMOST.equals(reportLevel)) {
store.setValue(Constants.REPORT_LEVEL,
Constants.REPORT_EVERY);
updateMemLeakAlso = true;
}
if (updateMemLeakAlso && runView != null) {
activeTreeItem = null;
// set view content
runView.setInput(getResults(false));
// refresh view
runView.refresh();
// if last selected item not found current item list
if (activeTreeItem == null) {
runView.setAutoExpandLevel(2);
} else {
// set selection to correct item
runView.setSelection(new StructuredSelection(
activeTreeItem), true);
}
}
if (callstackView != null) {
// update view callstack view content
callstackView.setInput(getCallStack(activeTreeItem));
// expand all the trees on call stack view
callstackView.expandAll();
}
// change tooltip
changeReportActionTooltip();
}
});
}
/**
* Change logging mode.
*
* @param loggingMode
* Used logging mode
*/
public final void changeLogTarget(final String loggingMode) {
if (logTargetMenu == null) {
return;
}
// get preference store
IPreferenceStore store = Activator.getPreferences();
String usedLoggingMode = "";
// if no logging mode given get it from the AnalyzeTool preferences
if (loggingMode == null) {
usedLoggingMode = store.getString(Constants.LOGGING_MODE);
}
// logging mode is given => so start to use it
else {
store.setValue(Constants.LOGGING_MODE, loggingMode);
usedLoggingMode = loggingMode;
}
if (Constants.LOGGING_S60.equals(usedLoggingMode)) {
logTargetMenu.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_CELLURAR));
logTargetMenu
.setToolTipText(Constants.ACTION_CHANGE_LOGGING_MODE_TOOLTIP_S60);
if (loggingMode == null) {
s60LogTargetAction.setChecked(true);
externalFastLogTargetAction.setChecked(false);
askLogTargetAction.setChecked(false);
}
} else if (Constants.LOGGING_EXT_FAST.equals(usedLoggingMode)) {
logTargetMenu.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_COMPUTER_FAST));
logTargetMenu
.setToolTipText(Constants.ACTION_CHANGE_LOGGING_MODE_TOOLTIP_FAST);
if (loggingMode == null) {
s60LogTargetAction.setChecked(false);
externalFastLogTargetAction.setChecked(true);
askLogTargetAction.setChecked(false);
}
}
// current logging mode is "ask_always"
else {
logTargetMenu.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_ASK));
logTargetMenu
.setToolTipText(Constants.ACTION_CHANGE_LOGGING_MODE_TOOLTIP_ASK);
if (loggingMode == null) {
s60LogTargetAction.setChecked(false);
externalFastLogTargetAction.setChecked(false);
askLogTargetAction.setChecked(true);
}
}
// if the fast data gathering mode is enabled by the preference page =>
// enable also toolbar option
// else disable fast data gathering mode
externalFastLogTargetAction.setEnabled(store
.getBoolean(Constants.LOGGING_FAST_ENABLED));
}
/**
* Changes "Change report detail level" action tooltip.
*/
public final void changeReportActionTooltip() {
if (changeDetails == null) {
return;
}
// get preference store
IPreferenceStore store = Activator.getPreferences();
// get active report level
String reportLevel = store.getString(Constants.REPORT_LEVEL);
// set new report level
if (Constants.REPORT_EVERY.equals(reportLevel)) {
changeDetails.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_DETAILS_ALL));
changeDetails
.setToolTipText(Constants.ACTION_CHANGE_REPORT_LEVEL_ALL);
} else if (Constants.REPORT_KNOWN.equals(reportLevel)) {
changeDetails.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_DETAILS_KNOWN));
changeDetails
.setToolTipText(Constants.ACTION_CHANGE_REPORT_LEVEL_KNOWN);
} else if (Constants.REPORT_TOPMOST.equals(reportLevel)) {
changeDetails.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_DETAILS_TOPMOST));
changeDetails
.setToolTipText(Constants.ACTION_CHANGE_REPORT_LEVEL_TOPMOST);
}
}
/**
* Change view title.
*
* @param newTitle
* New title text
*/
private void changeViewTitle(final String newTitle) {
// if newTitle contains text
if (newTitle != null) {
super.setContentDescription(newTitle);
}
}
/**
* Check that selected project is open and project information can be read.
*
* @return True if project is open and accessible otherwise False
*/
public final boolean checkProjectValidity() {
// project is not selected show info to user
if (project == null || !project.isOpen()) {
Util.showMessage(Constants.NO_PROJ_SELECT);
return false;
}
return true;
}
/**
* Cleans atool.exe made changes.
*/
public final void clean() {
if (!checkProjectValidity()) {
return;
}
// check is atool.exe available
if (!Util.isAtoolAvailable()) {
showErrorMessage(Constants.INFO_ATOOL_NOT_AVAILABLE);
return;
}
// ask for user
boolean ret = Util.openConfirmationDialog(Constants.CONFIRM_DELETE_ALL);
// if user confirms
if (ret) {
// clear AnalyzeTool made changes
Util.clearAtoolChanges(project);
cleanAnalyzeData(null);
resetGraphView();
updateChangeDetailState(project);
}
if (statisticView != null) {
statisticView.clean(null);
}
}
/**
* Cleans all the saved data.
*/
private void cleanAnalyzeData(final IProject projectRef) {
// clean all data if project not specified
if (projectRef == null) {
// clean all the project related info and data
projectResults.clear();
projectModules.clear();
} else {
// clear only one project results
if (projectResults.contains(projectRef)) {
projectResults.clearProjectData(projectRef);
}
if (projectModules.contains(projectRef)) {
projectModules.remove(projectRef);
}
}
cppFileNames.clear();
// update variables
activeTreeItem = null;
usedDataFileName = "";
// set default view contents
if (runView != null) {
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
runView.setInput(getStartupContent());
if (informationLabel != null) {
updateInformationLabel("");
}
changeViewTitle(viewTitle);
if (statisticView != null) {
statisticView.clean(projectRef);
}
}
});
}
clearCallstackViewContent();
if (clearProjectResults != null && clearProjectResults != null) {
clearProjectResults.setEnabled(false);
} else if (clearProjectResults != null) {
updateChangeDetailState(projectRef);
}
}
/**
* Clears callstack view contents.
*/
private void clearCallstackViewContent() {
if (runView == null) {
return;
}
// if view exists
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
if (callstackView != null) {
callstackView.setInput(null);
}
}
});
}
/**
* Contributes action bar.
*/
private void contributeToActionBars() {
if (getViewSite() == null) {
return;
}
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
@Override
public void createPartControl(Composite parent) {
// create a new Tab
final CTabFolder mainFolder = new CTabFolder(parent, SWT.TOP);
// create main view and add it tab
createMainView(mainFolder);
// create graph
createGraphView(mainFolder);
// set initial selection
mainFolder.setSelection(mainTab);
mainFolder.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
public void widgetSelected(SelectionEvent e) {
// if we changed to the graph tab and the graph load job isn't
// already running
// schedule it now
if (graphLoadJob != null
&& graphLoadJob.getState() != Job.RUNNING
&& mainFolder.getSelection() != null
&& mainFolder.getSelection().getControl() == chart) {
graphLoadJob.schedule();
}
if (mainFolder.getSelectionIndex() == 1) {
changeDetails.setEnabled(false);
} else {
changeDetails.setEnabled(true);
}
}
});
// stop any jobs that may be scheduled
mainFolder.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (graphLoadJob != null) {
graphLoadJob.cancel();
graphLoadJob = null;
}
if (analyzeJob != null) {
analyzeJob.cancel();
analyzeJob = null;
}
}
});
}
/**
* Creates graph view and add it to graph tab
*
* @param mainFolder
* CTabFolder parent of the view
*/
private void createGraphView(CTabFolder mainFolder) {
final CTabItem chartTabItem = new CTabItem(mainFolder, SWT.NONE);
chartTabItem.setText("Graph");
chartTabItem.setToolTipText("AnalyzeTool graph per process");
chart = new ChartContainer(mainFolder, SWT.NONE);
chartTabItem.setControl(chart);
IMemoryActivityModel model = AnalyzeFactory.getEmptyModel();
chart.setInput(project, model);
model.addProcesses(model.getProcesses());// charts should get notified
// via listeners on the
// model
}
/**
* Clears the graph by setting an empty model and causing paint events
*/
private void resetGraphView() {
if (chart != null) {
chart.setInput(project, AnalyzeFactory.getEmptyModel());
}
}
/**
* Creates new statistic view and add it to memory tab
*
* @param parent
* Statistic view parent( CTabFolder )
*/
public void createMemoryView(CTabFolder parent) {
statisticView = new StatisticView();
memoryTab = statisticView.createView(parent);
}
/**
* Creates memory results view
*
* @param parent
* View parent ( CTabFolder )
*/
public void createMainView(CTabFolder parent) {
// Create SashForm this form includes all the current view components
SashForm sashForm = new SashForm(parent, SWT.HORIZONTAL);
mainTab = new CTabItem(parent, SWT.NONE);
mainTab.setControl(sashForm);
mainTab.setText(Constants.MAIN_TAB_TITLE);
// create new treeviewer to shown memory analysis runs and leaks
runView = new TreeViewer(sashForm, SWT.VIRTUAL);
// create SashForm to display call stack addresses and more detailed
// information
// of selected run or leak
SashForm callstackForm = new SashForm(sashForm, SWT.VERTICAL);
// set content and label providers
runView.setContentProvider(new ViewContentProvider());
runView.setLabelProvider(new ViewLabelProvider());
// get init content
runView.setInput(getStartupContent());
// add listener to provide selection change events
runView.addTreeListener(this);
runView.setAutoExpandLevel(2);
// create new information label
// this label contains more detailed information of selected item
informationLabel = new Label(callstackForm, SWT.BORDER | SWT.CENTER);
// create grid data => this provides layout changes
GridData data = new GridData();
// add grid data to label, this enables label ui modifications e.g. line
// feed
informationLabel.setLayoutData(data);
// set init text
informationLabel.setText(Constants.INFO_NO_DATA);
// create new call stack view
// this components contains information of one memory leak call stack
// addresses
callstackView = new TreeViewer(callstackForm, SWT.MULTI | SWT.H_SCROLL
| SWT.V_SCROLL);
// modify UI components layouts
// reserve more space for left side of UI
sashForm.setWeights(new int[] { 5, 3 });
callstackForm.setWeights(new int[] { 2, 8 });
// add content and label providers
callstackView.setContentProvider(new ViewContentProvider());
callstackView.setLabelProvider(new ViewLabelProvider());
// make actions and construct click listeners
makeActions();
hookContextMenu();
hookDoubleClickAction();
hookClicks();
contributeToActionBars();
// set view title
viewTitle = String.format(Constants.ANALYZE_TOOL_TITLE_WITH_VERSION,
Util.getAToolFeatureVersionNumber());
this.setContentDescription(viewTitle);
// add selection listener
if (getSite() != null) {
getSite().getPage().addSelectionListener(this);
runView.getControl().addKeyListener(this);
}
// set actionlistener
Activator.setActionListener(this);
// set help shortcuts
PlatformUI.getWorkbench().getHelpSystem().setHelp(
callstackView.getControl(),
AnalyzeToolHelpContextIDs.ANALYZE_MAIN);
PlatformUI.getWorkbench().getHelpSystem().setHelp(runView.getControl(),
AnalyzeToolHelpContextIDs.ANALYZE_MAIN);
ResourcesPlugin.getWorkspace().addResourceChangeListener(
new ATResourceListener());
IPreferenceStore store = Activator.getPreferences();
store.setValue(Constants.LOGGING_FAST_ENABLED, true);
// get default value for logging mode
preferenceChanged();
}
/**
* When AnalyzeTool view is activated and TraceViewer plug-in is not
* available disable AnalyzeTool trace actions.
*
* @see com.nokia.s60tools.analyzetool.ui.IActionListener#disableTraceActions(boolean)
*
* @param disable
* Boolean state of trace action
*/
public void disableTraceActions(final boolean disable) {
if (traceAction != null && disable) {
// enable trace action
traceAction.setToolTipText(Constants.ACTION_START_TRACE);
traceAction.setEnabled(disable);
} else if (traceAction != null && !disable) {
// disable trace action
traceAction.setToolTipText(Constants.TRACE_NOT_FOUND);
traceAction.setEnabled(disable);
}
traceActive = false;
}
/**
* Fills context menu.
*
* @param manager
* Menu manager
*/
private void fillContextMenu(IMenuManager manager) {
manager.add(buildWithAtool);
manager.add(new Separator());
manager.add(traceAction);
manager.add(startSubtest);
manager.add(stopSubtest);
manager.add(new Separator());
manager.add(changeDetails);
manager.add(refreshResults);
manager.add(clearProjectResults);
manager.add(new Separator());
manager.add(cleanAtoolChanges);
manager.add(copyAction);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
/**
* Fills local pull down menu.
*
* @param manager
* Menu manager
*/
private void fillLocalPullDown(IMenuManager manager) {
manager.add(buildWithAtool);
manager.add(new Separator());
manager.add(traceAction);
manager.add(startSubtest);
manager.add(stopSubtest);
manager.add(new Separator());
manager.add(changeDetails);
manager.add(refreshResults);
manager.add(new Separator());
manager.add(cleanAtoolChanges);
manager.add(new Separator());
manager.add(openPrefs);
}
/**
* Fills local toolbar.
*
* @param manager
* Menu manager
*/
private void fillLocalToolBar(IToolBarManager manager) {
logTargetMenu = new DropDownMenu(Constants.ACTION_SAVE, this, false,
false);
makeLogTargetActions();
logTargetMenu.addAction(externalFastLogTargetAction);
logTargetMenu.addAction(s60LogTargetAction);
logTargetMenu.addAction(askLogTargetAction);
manager.add(logTargetMenu);
manager.add(buildWithAtool);
manager.add(new Separator());
manager.add(traceAction);
manager.add(startSubtest);
manager.add(stopSubtest);
manager.add(new Separator());
manager.add(changeDetails);
manager.add(new Separator());
fileOpenMenu = new DropDownMenu(Constants.ACTION_OPEN, this, false,
true);
makeFileOpenActions();
manager.add(fileOpenMenu);
// get drop down menu for save action
saveFileMenu = new DropDownMenu(Constants.ACTION_SAVE, this, true,
false);
saveFileMenu.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_SAVE));
saveFileMenu.addAction(saveReportAction);
saveFileMenu.addAction(saveDataFileAction);
manager.add(saveFileMenu);
manager.add(new Separator());
manager.add(cleanAtoolChanges);
manager.add(new Separator());
manager.add(openPrefs);
}
/**
* Gets call stack information of current leak.
*
* @param treeObject
* Tree object
* @return Object
*/
Object getCallStack(final TreeObject treeObject) {
IPreferenceStore store = Activator.getPreferences();
// if project is not selected or treeobject is not created
// => leave
if (project == null || treeObject == null) {
return null;
}
// set active tree item
activeTreeItem = treeObject;
AnalysisItem item = null;
if (treeObject.isSubTest()) {
item = projectResults.getSubtestItem(project,
treeObject.getRunID(), treeObject.getMemLeakID(),
treeObject.getSubtestID());
}
// get AnalysisItem
else {
item = projectResults.getSpecific(project, treeObject.getRunID(),
treeObject.getMemLeakID());
}
if (item == null) {
return null;
}
if (store == null) {
return null;
}
AbstractList<MMPInfo> modules = projectModules.get(project);
TreeHelper helper = new TreeHelper(null, store);
TreeParent parent = helper.getCallstack(item, modules);
return parent;
}
/**
* Gets callstack item name.
*
* @param callstackItem
* One callstack item
* @return Callstack name if found otherwise null
*/
public final String getCallstackItemName(final CallstackItem callstackItem) {
// if call stack item not set => return
if (callstackItem == null) {
return null;
}
String cppFileName = "";
String fileName = callstackItem.getFileName().toLowerCase(Locale.US);
if (fileName.indexOf(".cpp") == -1) {
return null;
}
// check that project contains cpp file which is parsed from call stack
// list
Iterator<String> iterCppFiles = cppFileNames.iterator();
while (iterCppFiles.hasNext()) {
String cppFileLocation = iterCppFiles.next();
// parse file name from the source path
int slash = Util.getLastSlashIndex(cppFileLocation);
if (slash != -1) {
String cppFile = cppFileLocation.substring(slash + 1,
cppFileLocation.length());
if (cppFile.equalsIgnoreCase(fileName)) {
cppFileName = cppFileLocation;
break;
}
}
}
return cppFileName;
}
/**
* Gets file info for current project.
*
* @param projectRef
* Project reference
*/
private void getFileInfos(final IProject projectRef) {
ResourceVisitor visitor = new ResourceVisitor(this);
// go thru all open projects
// this enables to display one memory address corresponding source code
// line
// for outside of active project
try {
if (projectRef == null) {
IWorkspaceRoot myWorkspaceRoot = ResourcesPlugin.getWorkspace()
.getRoot();
IProject[] projects = myWorkspaceRoot.getProjects();
for (int i = 0; i < projects.length; i++) {
IProject tempProject = projects[i];
if (tempProject.isOpen()) {
tempProject.accept(visitor);
}
}
} else { // project is selected
// if project is open => accept resource visitor
if (projectRef.isOpen()) {
projectRef.accept(visitor);
}
}
} catch (CoreException e) {
e.printStackTrace();
}
}
/**
* Gets project results.
*
* @param projectRef
* Project reference
*/
public void getProjectResults(final IProject projectRef) {
// if project reference is null => leave
if (projectRef == null) {
return;
}
// if project is selected and it is open
else if (projectRef.isOpen()) {
// if this is the first time to get project results
if (lastProjectRef == null) {
lastProjectRef = projectRef;
updateBuildState(lastProjectRef);
updateChangeDetailState(lastProjectRef);
}
// project selection changed
// need to get selected project results and mmp file info
else if (!lastProjectRef.equals(projectRef)) {
activeTreeItem = null;
lastProjectRef = projectRef;
runView.setInput(getResults(false));
callstackView.setInput(getCallStack(null));
updateInformationLabel("");
updateBuildState(lastProjectRef);
updateChangeDetailState(lastProjectRef);
}
}
// update clear project results action state
if (projectResults.contains(projectRef)) {
clearProjectResults.setEnabled(true);
} else {
clearProjectResults.setEnabled(false);
}
}
/**
* Gets memory leak analysis results.
*
* @param showErrorInfo
* Display error info or not
* @return Object memory leak analysis results
*/
private Object getResults(final boolean showErrorInfo) {
try {
// create a new tree parent
TreeParent testRuns = new TreeParent(Constants.TEST_RUNS_TREE_TITLE);
invisibleRoot = null;
invisibleRoot = new TreeParent(Constants.TREE_TITLE);
invisibleRoot.addChild(testRuns);
// if current project does not contain results => just update
// default view values
if (!projectResults.contains(project)) {
changeViewTitle(viewTitle);
updateInformationLabel(Constants.INFO_NO_DATA);
return getStartupContent();
}
if (!projectModules.containsKey(project)) {
AbstractList<MMPInfo> modules = Util
.loadProjectTargetsInfo(project);
projectModules.put(project, modules);
}
// get run results
AbstractList<RunResults> runs = projectResults.getResults(project);
AbstractList<MMPInfo> modules = projectModules.get(project);
// if no results available => show default view content
if (runs == null || runs.isEmpty()) {
changeViewTitle(viewTitle);
updateInformationLabel(Constants.INFO_NO_DATA);
// because no results created => delete project empty results
projectResults.clearProjectData(project);
fileOpenHistory.removeFileName(projectResults
.getDataFileName(project));
// display info to user
if (showErrorInfo) {
showErrorMessage(Constants.INFO_FILE_INVALID);
}
return getStartupContent();
}
IPreferenceStore store = Activator.getPreferences();
// create TreeHelper object
// TreeHelper class creates tree model to this view.
TreeHelper helper = new TreeHelper(lastSelectedObject, store);
// clear active item
activeTreeItem = null;
// update used data file name
usedDataFileName = projectResults.getDataFileName(project);
// change view title
changeViewTitle(viewTitle + " results from file: "
+ usedDataFileName);
// thru runs
Iterator<RunResults> runIterator = runs.iterator();
while (runIterator.hasNext()) {
// get one run info
RunResults oneRunResults = runIterator.next();
// creates one run information at the time
TreeParent oneRunTree = helper.createRunResults(oneRunResults,
modules);
// get active item
// active must ask from the TreeHelper class
// because it can be filtered out when creating new tree model
activeTreeItem = helper.getActiveItem();
testRuns.addChild(oneRunTree);
}
} catch (java.lang.NullPointerException npe) {
npe.printStackTrace();
return null;
}
// expand to runs level
runView.setAutoExpandLevel(2);
return invisibleRoot;
}
/**
* Sets startup contents for view.
*
* @return Object which can be displayd
*/
public TreeParent getStartupContent() {
// create default treeviewer content
invisibleRoot = new TreeParent(Constants.ANALYZE_TOOL_TITLE);
TreeParent child = new TreeParent(Constants.INFO_NO_DATA_FILE_AVAILABLE);
invisibleRoot.addChild(child);
return invisibleRoot;
}
/**
* Adds selection changed listener to view.
*/
private void hookClicks() {
runView.addSelectionChangedListener(this);
}
/**
* Hooks context menu.
*/
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@SuppressWarnings("synthetic-access")
public void menuAboutToShow(IMenuManager manager) {
MainView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(runView.getControl());
runView.getControl().setMenu(menu);
if (getSite() != null) {
getSite().registerContextMenu(menuMgr, runView);
}
}
/**
* Hook double click actions.
*/
private void hookDoubleClickAction() {
callstackView.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
doubleClickAction.run();
}
});
}
/**
* Check that if subtest by given name already exists.
*
* @param subTestName
* Subtest name
* @param target
* Testing target
* @return True if already exists otherwise False
*/
public final boolean isSubtestExists(final String subTestName,
final String target) {
Iterator<ActiveSubtests> subTestIter = startedSubtest.iterator();
while (subTestIter.hasNext()) {
ActiveSubtests oneSubtest = subTestIter.next();
if (oneSubtest.getName().equals(subTestName)
&& oneSubtest.getTargetName().equals(target)) {
return true;
}
}
return false;
}
/**
* Go thru the project files and stores mmp files.
*
* @param resource
* One resource file of project
*/
public final void loadFileInfo(IResource resource) {
// get all the cpp file info which are imported to workspace
// this enable pinpointing the code line for outside active project cpp
// file than
// the memory analysis is made
// get cpp file info
String cppFileName = Util.getCPPFileNameAndPath(resource);
// if cpp file found, save it
if (cppFileName != null && !cppFileNames.contains(cppFileName)) {
this.cppFileNames.add(cppFileName);
}
}
/**
* Construct all the actions.
*/
private void makeActions() {
// listens click actions
clickAction = new Action() {
@Override
public void run() {
// get selection
ISelection selection = runView.getSelection();
// get selection object
Object obj = ((IStructuredSelection) selection)
.getFirstElement();
// if object exists
if (obj == null) {
copyAction.setEnabled(false);
return;
}
// get call stack addresses to view
if (obj instanceof TreeObject) {
lastSelectedObject = obj;
// get callstack items
Object resultObject = getCallStack((TreeObject) obj);
// if results not found
if (resultObject == null) {
copyAction.setEnabled(false);
} else {
callstackView.setInput(resultObject);
copyAction.setEnabled(true);
}
}
// expand all the trees on call stack view
callstackView.expandAll();
setTextToInformationLabel();
}
};
// listens double click actions
doubleClickAction = new Action() {
@Override
public void run() {
// get selection
ISelection selection = callstackView.getSelection();
Object obj = ((IStructuredSelection) selection)
.getFirstElement();
// open file in editor
if (obj instanceof TreeObject) {
openEditor((TreeObject) obj);
}
}
};
// data capture
traceAction = new Action() {
@Override
public void run() {
// if trace is active => stop the trace
if (traceActive) {
stop(true);
}
// if trace is not active => start the trace
else {
start();
}
}
};
traceAction.setText(Constants.ACTION_START_TRACE);
traceAction.setToolTipText(Constants.ACTION_START_TRACE);
traceAction.setImageDescriptor(Activator
.getImageDescriptor((Constants.BUTTON_RUN)));
// if trace actions are disabled
if (!enableTrace) {
traceAction.setEnabled(false);
traceAction.setToolTipText(Constants.TRACE_NOT_FOUND);
}
// build with atool
buildWithAtool = new Action() {
@Override
public void run() {
activateAnalysisBuild();
}
};
buildWithAtool.setText(Constants.ACTION_AT_BUILD_ACTIVE);
buildWithAtool.setToolTipText(Constants.ACTION_AT_BUILD_ACTIVE);
buildWithAtool.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_BUILD));
// clean atool changes
cleanAtoolChanges = new Action() {
@Override
public void run() {
clean();
}
};
cleanAtoolChanges.setText(Constants.ACTION_CLEAR_CHANGES);
cleanAtoolChanges
.setToolTipText(Constants.ACTION_CLEAR_CHANGES_TOOLTIP);
cleanAtoolChanges.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_CLEAN));
// change detail level
changeDetails = new Action() {
@Override
public void run() {
changeDetailLevel();
}
};
changeDetails.setText(Constants.ACTION_CHANGE_REPORT_LEVEL);
// save report( xml ) file
saveReportAction = new Action() {
@Override
public void run() {
saveReportFile(Constants.SAVE_REPORT_FILE_XML);
}
};
saveReportAction.setText(Constants.ACTION_SAVE_REPORT);
saveReportAction.setToolTipText(Constants.ACTION_SAVE_REPORT);
// save data file
saveDataFileAction = new Action() {
@Override
public void run() {
saveReportFile(Constants.SAVE_REPORT_FILE_DATA);
}
};
saveDataFileAction.setText(Constants.ACTION_SAVE_DATA);
saveDataFileAction.setToolTipText(Constants.ACTION_SAVE_DATA);
// start subtest
startSubtest = new Action() {
@Override
public void run() {
startSubTest();
}
};
startSubtest.setText(Constants.ACTION_START_SUBTEST);
startSubtest.setToolTipText(Constants.ACTION_START_SUBTEST);
startSubtest.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_START_SUBTEST));
// stop subtest
stopSubtest = new Action() {
@Override
public void run() {
stopSubTest();
}
};
stopSubtest.setText(Constants.ACTION_STOP_SUBTEST);
stopSubtest.setToolTipText(Constants.ACTION_STOP_SUBTEST);
stopSubtest.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_STOP_SUBTEST));
stopSubtest.setDescription(Constants.ACTION_STOP_SUBTEST);
// set start and stop subtest not visible at the beginning
startSubtest.setEnabled(false);
stopSubtest.setEnabled(false);
analyzeResults = new Action() {
@Override
public void run() {
analyzeDataFile(Constants.ANALYZE_ASK_FOR_USER, null, true);
}
};
analyzeResults.setText(Constants.ACTION_OPEN);
analyzeResults.setToolTipText(Constants.ACTION_OPEN);
analyzeResults.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_OPEN));
clearProjectResults = new Action() {
@Override
public void run() {
cleanAnalyzeData(project);
if (statisticView != null) {
statisticView.clean(project);
}
updateChangeDetailState(project);
}
};
clearProjectResults.setText(Constants.ACTION_CLEAR_RESULTS);
clearProjectResults.setToolTipText(Constants.ACTION_CLEAR_RESULTS);
refreshResults = new Action() {
@Override
public void run() {
if (project != null && project.isOpen()
&& projectResults != null) {
String dataFile = projectResults.getDataFileName(project);
if (dataFile != null || !("").equals(dataFile)) {
analyzeDataFile(Constants.ANALYZE_USE_DATA_FILE,
dataFile, true);
} else {
// some internal error occurred => disable this action
refreshResults.setEnabled(false);
}
}
}
};
refreshResults.setText(Constants.ACTION_RE_ANALYZE);
refreshResults.setToolTipText(Constants.ACTION_RE_ANALYZE_TOOLTIP);
refreshResults.setEnabled(false);
// copy active item contents to clipboard
copyAction = new Action() {
@Override
public void run() {
// copy active item contents to clipboard
// Create new clipboard object
Clipboard cp = new Clipboard(runView.getControl().getDisplay());
// Create new TextTransfer object
// TextTransfer converts plain text represented as a java String
// to a platform specific representation of the data and vice
// versa
TextTransfer tt = TextTransfer.getInstance();
// new StringBuffer which contains the copied text
StringBuffer sb = new StringBuffer(64);
// chech that project contains results
if (projectResults == null || !projectResults.contains(project)
|| activeTreeItem == null) {
return;
}
// get active item info (also callstack info)
AnalysisItem item = null;
// if selected item is subtest
if (activeTreeItem.isSubTest()) {
item = projectResults.getSubtestItem(project,
activeTreeItem.getRunID(), activeTreeItem
.getMemLeakID(), activeTreeItem
.getSubtestID());
} else {
item = projectResults.getSpecific(project, activeTreeItem
.getRunID(), activeTreeItem.getMemLeakID());
}
// check that item found
if (item == null) {
return;
}
sb.append(activeTreeItem.getName());
String separator = System.getProperty("line.separator");
sb.append(separator);
char space = ' ';
AbstractList<CallstackItem> callstackItems = item
.getCallstackItems();
Iterator<CallstackItem> iterCallstack = callstackItems
.iterator();
while (iterCallstack.hasNext()) {
CallstackItem oneItem = iterCallstack.next();
sb.append(" ");
sb.append(oneItem.getMemoryAddress());
sb.append(space);
sb.append(oneItem.getModuleName());
sb.append(space);
sb.append(oneItem.getFunctionName());
sb.append(space);
sb.append(oneItem.getFileName());
sb.append(space);
int lineNbr = oneItem.getLeakLineNumber();
if (lineNbr > 0) {
sb.append(lineNbr);
}
sb.append(separator);
}
// info is ready => now copy info to clipboard
cp.setContents(new Object[] { sb.toString() },
new Transfer[] { tt });
}
};
copyAction.setText(Constants.ACTION_COPY);
copyAction.setEnabled(false);
// open preferences action
openPrefs = new Action() {
@Override
public void run() {
PreferenceDialog dialog = PreferencesUtil
.createPreferenceDialogOn(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell(),
Constants.ANALYZE_TOOL_PREFS_ID, null, null);
if (dialog != null) {
dialog.open();
}
}
};
openPrefs.setText(Constants.ACTION_OPEN_PREFS);
openPrefs.setToolTipText(Constants.ACTION_OPEN_PREFS_TOOLTIP);
openPrefs.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_OPEN_PREFS));
changeReportActionTooltip();
updateChangeDetailState(project);
updateBuildState(project);
}
/**
* Creates file open actions.
*/
private void makeFileOpenActions() {
fileOpenMenu.setText(Constants.ACTION_OPEN);
fileOpenMenu.setToolTipText(Constants.ACTION_OPEN);
fileOpenMenu.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_OPEN));
}
/**
* Creates data gathering actions.
*/
private void makeLogTargetActions() {
s60LogTargetAction = new Action(Constants.LOGGING_S60,
IAction.AS_RADIO_BUTTON) {
@Override
public void run() {
changeLogTarget(Constants.LOGGING_S60);
}
};
s60LogTargetAction.setText(Constants.PREFS_S60);
s60LogTargetAction
.setToolTipText(Constants.ACTION_CHANGE_LOGGING_MODE_TOOLTIP_S60);
s60LogTargetAction.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_CELLURAR));
externalFastLogTargetAction = new Action(Constants.LOGGING_EXT_FAST,
IAction.AS_RADIO_BUTTON) {
@Override
public void run() {
changeLogTarget(Constants.LOGGING_EXT_FAST);
}
};
externalFastLogTargetAction.setText(Constants.PREFS_EXT_FAST);
externalFastLogTargetAction
.setToolTipText(Constants.PREFS_EXT_FAST_TOOLTIP);
externalFastLogTargetAction.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_COMPUTER_FAST));
askLogTargetAction = new Action(Constants.LOGGING_ASK_ALLWAYS,
IAction.AS_RADIO_BUTTON) {
@Override
public void run() {
changeLogTarget(Constants.LOGGING_ASK_ALLWAYS);
}
};
askLogTargetAction.setText(Constants.PREFS_ASK_ALWAYS);
askLogTargetAction
.setToolTipText(Constants.ACTION_CHANGE_LOGGING_MODE_TOOLTIP_ASK);
askLogTargetAction.setImageDescriptor(Activator
.getImageDescriptor(Constants.BUTTON_ASK));
}
/**
* Displays selected callstack item location on default file editor.
*
* @param treeObject
* Tree object
*/
public final void openEditor(final TreeObject treeObject) {
// get file info for all projects
getFileInfos(project);
try {
// if no project selected
if (project == null || !project.isOpen()) {
Util.showMessage(Constants.NO_PROJ_SELECT);
return;
}
// get selected call stack item
CallstackItem callstackItem = treeObject.getCallstackItem();
if (callstackItem == null) {
return;
}
String cppFileName = getCallstackItemName(callstackItem);
if (cppFileName == null || ("").equals(cppFileName)) {
cppFileName = callstackItem.getFileName();
}
// if leak number is invalid => leave
if (callstackItem.getLeakLineNumber() < 1) {
return;
}
String line = Integer.toString(callstackItem.getLeakLineNumber());
IFile file = null;
if (project.isOpen()) {
file = ResourcesPlugin.getWorkspace().getRoot().getFile(
new Path(project.getName() + "\\" + cppFileName));
}
// if file not found in active project
// go thru all open projects in current workbench
if (file == null || !file.exists()) {
IWorkspaceRoot myWorkspaceRoot = ResourcesPlugin.getWorkspace()
.getRoot();
IProject[] projects = myWorkspaceRoot.getProjects();
for (int i = 0; i < projects.length; i++) {
file = ResourcesPlugin.getWorkspace().getRoot()
.getFile(
new Path(projects[i].getName() + "\\"
+ cppFileName));
// file found => skip the rest of the projects
if (file != null && file.exists()) {
break;
}
}
}
// if file still not found
// display info to user and leave
if (file == null || !file.exists()) {
Util.showMessage(Constants.SOURCE_NOT_FOUND);
return;
}
IWorkbenchPage page = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage();
HashMap<String, Object> map = new HashMap<String, Object>();
map.put(IMarker.LINE_NUMBER, Integer.parseInt(line));
map.put(IDE.EDITOR_ID_ATTR, Constants.SOURCE_FILE_EDITOR_ID);
IMarker marker = file.createMarker(IMarker.TEXT);
marker.setAttributes(map);
IDE.openEditor(page, marker);
} catch (NullPointerException npe) {
npe.printStackTrace();
} catch (CoreException ce) {
ce.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Updates log target action and report action tooltips.
*
* @see com.nokia.s60tools.analyzetool.ui.IActionListener#preferenceChanged()
*/
public void preferenceChanged() {
// get active logging mode
changeLogTarget(null);
changeReportActionTooltip();
}
/**
* Refresh AnalyzeTool view.
*/
public final void refreshView() {
// update display content
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
updateInformationLabel("");
// refresh view
runView.setInput(getResults(false));
// refresh callstack view
getCallStack(activeTreeItem);
if (project != null && project.isOpen()
&& projectResults.contains(project)) {
clearProjectResults.setEnabled(true);
} else {
clearProjectResults.setEnabled(false);
}
updateChangeDetailState(project);
}
});
}
/**
* Runs user selected AnalyzeTool action.
*
* @see com.nokia.s60tools.analyzetool.ui.IActionListener#runAction(IProject,
* com.nokia.s60tools.analyzetool.global.Constants.ACTIONS)
*
* @param projectRef
* Project reference
*
* @param action
* Which action to execute
*/
public void runAction(IProject projectRef, Constants.ACTIONS action) {
project = projectRef;
switch (action) {
case RUN_VIEW_MEM_LEAKS:
analyzeResults.run();
break;
case RUN_BUILD:
buildWithAtool.run();
break;
case RUN_CLEAN:
cleanAtoolChanges.run();
break;
default: // by design default statement is empty
break;
}
}
/**
* Copies existing report or data file to the new location. Asks from user
* new location where to copy the file.
*
* @param type
* Which kind of type the file is. Possible types XML or data
* file
*
* @return True if saving successfully otherwise false
*/
public final boolean saveReportFile(final int type) {
// copy success?
boolean success = false;
// check if project is selected
if (project == null) {
showMessage(Constants.NO_PROJ_SELECT);
return success;
}
// folder location
String folder = null;
// file path and name to use
String usedFile = null;
// save xml file
if (type == Constants.SAVE_REPORT_FILE_XML) {
String targetPath = Util.getBldInfFolder(project, true)
+ Constants.FILENAME_CARBIDE;
java.io.File file = new java.io.File(targetPath);
if (file.exists()) {
String[] names = new String[2];
names[0] = "*.xml";
names[1] = "*.*";
Shell shell = null;
// get shell from teh active view
if (runView != null) {
shell = runView.getControl().getShell();
}
// if for some reason shell is null => leave
if (shell == null) {
return success;
}
// ask user where to save xml report file
folder = Util.fileSaveDialog(Constants.DIALOG_SAVE_REPORT,
names, shell);
usedFile = targetPath;
} else {
Util.showMessage(Constants.INFO_NO_RESULTS_FILE);
return success;
}
}
// save data file
else {
String dataFile = Util.isDataFileAvailable(project);
// check is there data file which can be used
if ((dataFile == null || dataFile.equals(""))
&& (usedDataFileName == null || usedDataFileName.equals(""))) {
Util.showMessage(Constants.INFO_NO_DATA_FILE);
return success;
}
// if no existing data file opened
else if (usedDataFileName == null || usedDataFileName.equals("")) {
usedFile = dataFile;
}
// user is already opened data file => save it
else {
usedFile = usedDataFileName;
}
String[] names = new String[2];
names[0] = "*.dat";
names[1] = "*.*";
Shell shell = null;
// get shell from the active view
if (runView != null) {
shell = runView.getControl().getShell();
}
// if for some reason shell is null => leave
if (shell == null) {
return success;
}
// ask user where to save XML report file
folder = Util.fileSaveDialog(Constants.DIALOG_SAVE_TRACE, names,
shell);
}
// no folder selected
// user press "cancel" button;
if (folder == null) {
return success;
}
// copy file to folder
success = Util.copyFileToFolder(usedFile, folder);
// report to user
if (success) {
Util.showMessage(Constants.INFO_SAVE_SUCCESS + folder);
} else {
Util.showMessage(Constants.MAIN_CAN_NOT_COPY + usedFile);
}
return success;
}
/**
* Notifies this action delegate that the selection in the workbench has
* changed.
*
* @param part
* Workbench part
*
* @param selection
* User selection
*/
@SuppressWarnings("restriction")
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
// project reference
IProject selectedProject = null;
// Check where the selection comes from
// Supported views: CommonNavigator, SymbianProjectNavigatorView and
// ResourceNavigator
if (!(part instanceof CommonNavigator
|| part instanceof SymbianProjectNavigatorView || part instanceof ResourceNavigator)) {
return;
}
// get selection
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
// get first element of selection
Object element = structuredSelection.getFirstElement();
// check selection
if (element instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) element;
IResource resource = null;
if (adaptable instanceof IResource) {
resource = (IResource) adaptable;
} else if (adaptable instanceof org.eclipse.cdt.internal.ui.cview.IncludeRefContainer) {
selectedProject = ((org.eclipse.cdt.internal.ui.cview.IncludeRefContainer) adaptable)
.getCProject().getProject();
} else if (adaptable instanceof org.eclipse.cdt.core.model.ICProject) {
selectedProject = ((org.eclipse.cdt.core.model.ICProject) adaptable)
.getProject();
} else {
resource = (IResource) adaptable.getAdapter(IResource.class);
}
// resource found => get resource project
if (resource != null) {
selectedProject = resource.getProject();
}
}
// first item is null => update build state
else if (element == null) {
updateBuildState(null);
}
// if project found and it is open => get project results
if (selectedProject != null && selectedProject.isOpen()) {
project = selectedProject;
getProjectResults(selectedProject);
updateBuildState(project);
if (statisticView != null) {
statisticView.handleProjectChange(project);
}
}
}
/**
* Executes clickAction when user selects item in the AnalyzeTool view.
*
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*
* @param event
* Selection changed event
*/
public void selectionChanged(SelectionChangedEvent event) {
clickAction.run();
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
runView.getControl().setFocus();
}
/**
* Sets text to information label.
*/
public final void setTextToInformationLabel() {
if (activeTreeItem == null) {
return;
}
// run information
RunResults oneRunResults = projectResults.getRun(project,
activeTreeItem.getRunID());
// no results found => update label
if (oneRunResults == null) {
updateInformationLabel("");
} else {
StringBuffer buffer = new StringBuffer(32);
buffer.append("Run: ");
buffer.append(oneRunResults.getItemID());
buffer.append(" Memory leaks: ");
buffer.append(oneRunResults.getAnalysisItems().size());
buffer.append(" Handle leaks: ");
buffer.append(oneRunResults.getHandleLeaks().size());
if (("").equals(oneRunResults.getEndTime())) {
buffer.append("\nStart time: " + oneRunResults.getStartTime()
+ " \nEnd time: FAILED");
} else {
buffer.append("\nStart time: " + oneRunResults.getStartTime()
+ " \nEnd time: " + oneRunResults.getEndTime());
}
updateInformationLabel(buffer.toString());
}
}
/**
* Shows error message.
*
* @param message
* Error message to show
*/
public final void showErrorMessage(final String message) {
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
Util.showErrorMessage(message);
}
});
}
/**
* Shows message.
*
* @param message
* Message to show
*/
public final void showMessage(final String message) {
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
Util.showMessage(message);
}
});
}
/**
* Starts traceviewer connection.
*/
private void start() {
// check if the project is selected and open
if (!checkProjectValidity()) {
return;
}
// get project file infos
getFileInfos(project);
String dataFile = Util.isDataFileAvailable(project);
// if data file already exists, ask for overwrite
if (dataFile != null && !dataFile.equalsIgnoreCase("")) {
int saveDataFiles = Util
.openConfirmationDialogWithCancel(Constants.CONFIRM_OVERWRITE_FILE);
if (saveDataFiles == Constants.SAVE_DATA_FILE) {
if (!saveReportFile(Constants.SAVE_REPORT_FILE_DATA)) {
return;
}
} else if (saveDataFiles == Constants.SAVE_DATA_FILE_CANCEL) {
// user press "Cancel" so return and do nothing
return;
}
// delete existing data file
Util.deleteDataFile(project);
}
ICarbideProjectInfo info = CarbideBuilderPlugin.getBuildManager()
.getProjectInfo(project);
ICarbideBuildConfiguration config = info.getDefaultConfiguration();
// start listening emulator output
if (config.getPlatformString().equals(Constants.BUILD_TARGET_WINSCW)) {
String dbghelpDllVersionInfo = Util.getDbghelpDllVersionInfo(Util
.getAtoolInstallFolder());
if (dbghelpDllVersionInfo != Constants.DBGHELPDLL_IS_UP_TO_DATE) {
DbghelpDllVersionInfoDialog dialog = new DbghelpDllVersionInfoDialog(
getSite().getShell(), dbghelpDllVersionInfo);
if (dialog.open() == Window.CANCEL)
return;
}
listeningJob = new EpocReader(project, this);
listeningJob.start();
traceStarted();
return;
}
// else start trace capturing using TraceViewer connection
// main view class instance
// this instance if passed to the TraceWrapper class
final MainView selfInstance = this;
Job activateTrace = new Job(Constants.STARTING_TRACE) {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
// update progress monitor state
monitor.beginTask(Constants.STARTING_TRACE,
IProgressMonitor.UNKNOWN);
// load TraceWrapper class
Class<?> buildManagerClass = Class
.forName("com.nokia.s60tools.analyzetool.trace.TraceWrapper");
// get TraceWrapper class available methods
java.lang.reflect.Method[] methods = buildManagerClass
.getMethods();
// thru methods
for (int i = 0; i < methods.length; i++) {
// get one method
java.lang.reflect.Method oneMethod = methods[i];
// if method name is "connect"
if (oneMethod.getName().equalsIgnoreCase("connect")) {
// parameters for the connect method
Object[] objs = new Object[1];
objs[0] = selfInstance;
// call connect method
String returnValue = (String) oneMethod.invoke(
buildManagerClass.newInstance(), objs);
// if there was no errors while connection
if (("").equals(returnValue)) {
// invoke parser to open needed streams
parser.openStreams(Util.getBldInfFolder(
project, true));
traceStarted();
} else {
traceAction
.setImageDescriptor(Activator
.getImageDescriptor((Constants.BUTTON_RUN)));
traceActive = false;
showErrorMessage(returnValue);
}
}
}
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
} catch (SecurityException se) {
se.printStackTrace();
} catch (IllegalAccessException iae) {
iae.printStackTrace();
} catch (IllegalArgumentException iare) {
iare.printStackTrace();
} catch (java.lang.reflect.InvocationTargetException ite) {
ite.printStackTrace();
} catch (InstantiationException iv) {
iv.printStackTrace();
}
return new Status(IStatus.OK, Constants.ANALYZE_CONSOLE_ID,
IStatus.OK, "Trace started", null);
}
};
activateTrace.setUser(true);
activateTrace.schedule();
}
/**
* Starts subtests.
*/
public final void startSubTest() {
// get started processes
Hashtable<String, Integer> startedPros = null;
// if parser exists => means that the tracing is started and processes
// info is available
if (parser != null) {
startedPros = parser.getStartedProcesses();
}
// no processes = >show info and leave
if (startedPros == null || startedPros.isEmpty()) {
Util.showMessage(Constants.SUBTEST_NO_PROCESSES);
return;
}
// get started target info
AbstractList<String> targets = new ArrayList<String>();
for (java.util.Enumeration<String> e = startedPros.keys(); e
.hasMoreElements();) {
String processName = e.nextElement();
targets.add(processName);
}
// used target
String target = null;
// processes found, print info to user
if (targets.size() == 1) {
target = targets.get(0);
} else {
target = Util.openSelectionDialog(Constants.SUBTEST_SELECT_TARGET,
Constants.SUBTEST_RUNNING_PROCESSES_INFO, targets);
}
if (target == null || ("").equals(target)) {
return;
}
// ask for subtest name
CustomInputDialog dialog = new CustomInputDialog(
Constants.ANALYZE_TOOL_TITLE, Constants.SUBTEST_INPUT_NAME, "");
dialog.open();
String subTestName = dialog.getUserInput();
if (subTestName == null || subTestName.length() == 0) {
return;
}
// get process id for selected target
int processID = startedPros.get(target);
// if subtest already exists
if (isSubtestExists(subTestName, target)) {
Util.showMessage(Constants.SUBTEST_ALLREADY_RUNNING);
return;
}
// create new subtes object and add it to AbstractList
ActiveSubtests subtes = new ActiveSubtests(subTestName, target,
processID);
startedSubtest.add(subtes);
// start subtest
parser.parse(Constants.PREFIX + " " + subtes.getProcessID()
+ " TSS 0000 " + subTestName);
updateSubtestInfoText(Constants.SUBTEST_STARTED + target
+ Constants.ENRULE + subTestName);
stopSubtest.setEnabled(true);
}
/**
* Stop external message tracing.
*/
public final void stop(boolean analyze) {
ICarbideProjectInfo info = CarbideBuilderPlugin.getBuildManager()
.getProjectInfo(project);
ICarbideBuildConfiguration config = info.getDefaultConfiguration();
if (config.getPlatformString().equalsIgnoreCase(
Constants.BUILD_TARGET_WINSCW)) {
listeningJob.stop();
traceStopped(analyze);
return;
}
// else stop TraceViewer connection
try {
Class<?> buildManagerClass = Class
.forName("com.nokia.s60tools.analyzetool.trace.TraceWrapper");
java.lang.reflect.Method[] methods = buildManagerClass.getMethods();
for (int i = 0; i < methods.length; i++) {
java.lang.reflect.Method oneMethod = methods[i];
if (oneMethod.getName().equalsIgnoreCase("disconnect")) {
Object[] objs = new Object[1];
objs[0] = this;
String returnValue = (String) oneMethod.invoke(
buildManagerClass.newInstance(), new Object[] {});
if (("").equals(returnValue)) {
traceStopped(analyze);
} else {
showErrorMessage("Error while disconnecting TraceViewer");
traceAction.setImageDescriptor(Activator
.getImageDescriptor((Constants.BUTTON_STOP)));
traceActive = true;
}
}
}
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
} catch (SecurityException se) {
se.printStackTrace();
} catch (IllegalAccessException iae) {
iae.printStackTrace();
} catch (IllegalArgumentException iare) {
iare.printStackTrace();
} catch (java.lang.reflect.InvocationTargetException ite) {
ite.printStackTrace();
} catch (InstantiationException iv) {
iv.printStackTrace();
}
}
/**
* Updates button states and creates results for project.
*/
private void traceStopped(boolean analyze) {
// update icon and information text
traceAction.setImageDescriptor(Activator
.getImageDescriptor((Constants.BUTTON_RUN)));
traceAction.setText(Constants.ACTION_START_TRACE);
traceAction.setToolTipText(Constants.ACTION_START_TRACE);
traceActive = false;
// close any active subtests
if (!startedSubtest.isEmpty()) {
for (int j = 0; j < startedSubtest.size(); j++) {
ActiveSubtests oneSubtest = startedSubtest.get(j);
parser.parse(Constants.PREFIX + " " + oneSubtest.getProcessID()
+ " TSE 0000 " + oneSubtest.getName());
}
startedSubtest.clear();
}
// tell parser to finish => write data to file
parser.finish();
// inform user
updateLabel(Constants.INFO_TRACE_STOP);
// set start and stop trace not visible
startSubtest.setEnabled(false);
stopSubtest.setEnabled(false);
fileOpenMenu.setEnabled(true);
saveFileMenu.setEnabled(true);
cleanAtoolChanges.setEnabled(true);
project = traceStartedProjectRef;
// parse and analyze saved data file
if (analyze) {
analyzeDataFile(Constants.ANALYZE_USE_DATA_FILE, null, true);
}
}
/**
* Stop one subtest. If there is multiple subtests running ask for user to
* which one to stop.
*/
public final void stopSubTest() {
// no processes show info
if (startedSubtest.isEmpty()) {
Util.showMessage(Constants.SUBTEST_NO_SUBTESTS);
} else {
// only one subtest no need to ask for users
if (startedSubtest.size() == 1) {
ActiveSubtests oneSubtest = startedSubtest.get(0);
parser.parse(Constants.PREFIX + " " + oneSubtest.getProcessID()
+ " TSE 0000 " + oneSubtest.getName());
updateSubtestInfoText(Constants.SUBTEST_ENDED
+ oneSubtest.getTargetName() + Constants.ENRULE
+ oneSubtest.getName());
startedSubtest.remove(0);
stopSubtest.setEnabled(false);
} else { // multiple subtest found ask for the user which to stop
// multiple subtest found ask for user which to be ended
AbstractList<String> tmpSubtest = new ArrayList<String>();
// get list of active subtests
for (int i = 0; i < startedSubtest.size(); i++) {
ActiveSubtests oneSubtest = startedSubtest.get(i);
String tmpStr = oneSubtest.getTargetName()
+ Constants.ENRULE + oneSubtest.getName();
tmpSubtest.add(tmpStr);
}
String selection = Util.openSelectionDialog(
Constants.SUBTEST_SELECT_SUBTEST_TO_STOP, null,
tmpSubtest);
// thru active subtests
for (int k = 0; k < startedSubtest.size(); k++) {
// get one subtest
ActiveSubtests oneSubtest = startedSubtest.get(k);
// split user selected subtest information to get subtest
// name
String[] splittedText = selection.split(" ");
// if user selected subtest name and current subtest equals
if (splittedText[2].equals(oneSubtest.getName())) {
// write subtest end tag to data file
parser.parse(Constants.PREFIX + " "
+ oneSubtest.getProcessID() + " TSE 0000 "
+ oneSubtest.getName());
updateSubtestInfoText(Constants.SUBTEST_ENDED
+ oneSubtest.getTargetName() + Constants.ENRULE
+ oneSubtest.getName());
// remove current subtest from active subtest
// AbstractList
startedSubtest.remove(k);
break;
}
}
if (startedSubtest.isEmpty()) {
stopSubtest.setEnabled(false);
}
}
}
}
/**
* When AnalyzeTool view tree model is collapsed.
*
* @see org.eclipse.jface.viewers.ITreeViewerListener#treeCollapsed(org.eclipse.jface.viewers.TreeExpansionEvent)
*
* @param event
* Tree expansion event
*/
public void treeCollapsed(TreeExpansionEvent event) {
// MethodDeclaration/Block[count(BlockStatement) = 0 and
// @containsComment = 'false']
}
/**
* When AnalyzeTool view tree model is expanded.
*
* @see org.eclipse.jface.viewers.ITreeViewerListener#treeExpanded(org.eclipse.jface.viewers.TreeExpansionEvent)
*
* @param event
* Tree expansion event
*/
public void treeExpanded(TreeExpansionEvent event) {
// MethodDeclaration/Block[count(BlockStatement) = 0 and
// @containsComment = 'false']
}
/**
* Updates allocation count in the information label.
*
* The information layout is hard to modify so we need to manage information
* label text
*/
public final void updateAllocNumber() {
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
// if label is created
if (informationLabel != null) {
// get existing label text
String tmpText = informationLabel.getText();
// split existing text
String[] strArray = tmpText.split(lineFeed);
// if text contains more than 3 lines
if (strArray.length >= 2) {
// create new buffer
StringBuffer tmpBuffer = new StringBuffer(
strArray.length);
// set memory allocation size
strArray[1] = Constants.INFO_ALLOCATED_MEM
+ parser.getAllocationsSize();
// get updated text to buffer
for (int i = 0; i < strArray.length; i++) {
tmpBuffer.append(strArray[i]);
tmpBuffer.append(lineFeed);
}
// set new text to information label
informationLabel.setText(tmpBuffer.toString());
} else {
informationLabel.setText(tmpText + lineFeed
+ Constants.INFO_ALLOCATED_MEM
+ parser.getAllocationsSize());
}
}
}
});
}
/**
* Update build action icon and tooltip text.
*
* @param projectRef
* Project reference
*/
public final void updateBuildState(final IProject projectRef) {
if (buildWithAtool == null) {
return;
}
BuilderUtil util = new BuilderUtil();
// if project is not selected
if (projectRef == null) {
buildWithAtool.setText(Constants.ACTION_AT_BUILD_DEACTIVE);
buildWithAtool.setToolTipText(Constants.ACTION_AT_BUILD_DEACTIVE);
buildWithAtool.setChecked(false);
}
// if AnalyzeTool build is enabled
else if (util.isNatureEnabled(projectRef)) {
buildWithAtool.setText(Constants.ACTION_AT_BUILD_ACTIVE);
buildWithAtool.setToolTipText(Constants.ACTION_AT_BUILD_ACTIVE);
buildWithAtool.setChecked(true);
} else {
buildWithAtool.setText(Constants.ACTION_AT_BUILD_DEACTIVE);
buildWithAtool.setToolTipText(Constants.ACTION_AT_BUILD_DEACTIVE);
buildWithAtool.setChecked(false);
}
}
/**
* Indicates the target (emulator/device) by inspecting the given projects
* build configuration.
*
* @param selectedProject
* the currently active project
* @return "emulator" if the build configuration is WINSCW, "device"
* otherwise
*/
private static String getTraceTarget(final IProject selectedProject) {
String target = "";
if (selectedProject != null && selectedProject.isOpen()) {
ICarbideProjectInfo info = CarbideBuilderPlugin.getBuildManager()
.getProjectInfo(selectedProject);
if (info != null) {
ICarbideBuildConfiguration config = info
.getDefaultConfiguration();
target = config.getPlatformString().equals(
Constants.BUILD_TARGET_WINSCW) ? Constants.INFO_TRACE_FROM_EMULATOR
: Constants.INFO_TRACE_FROM_DEVICE;
}
}
return target;
}
/**
* Update change detail action state.
*
* @param projectRef
* Current project
*/
public final void updateChangeDetailState(final IProject projectRef) {
if (changeDetails == null) {
return;
}
if (projectRef == null) {
changeDetails.setEnabled(false);
refreshResults.setEnabled(false);
return;
} else if (projectResults.contains(projectRef)) {
changeDetails.setEnabled(true);
} else {
changeDetails.setEnabled(false);
}
String dataFile = projectResults.getDataFileName(projectRef);
if (dataFile != null) {
int fileType = UseAtool.checkFileType(dataFile);
if (fileType == Constants.DATAFILE_TRACE
|| fileType == Constants.DATAFILE_LOG
|| fileType == Constants.DATAFILE_BINARY) {
refreshResults.setEnabled(true);
} else {
refreshResults.setEnabled(false);
}
} else {
refreshResults.setEnabled(false);
}
}
/**
* Sets information to the information label.
*
* @param infoText
* Info text
*/
private void updateInformationLabel(final String infoText) {
// trace is active => do not update information label
if (traceActive) {
return;
}
// sync with the UI thread
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
// if informationlabel exists set text
if (informationLabel != null) {
informationLabel.setText(infoText);
}
}
});
}
/**
* Updates label by given string.
*
* @param line
* String to display
*/
public final void updateLabel(final String line) {
final String oneLine = line;
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
// if informationlabel exists set text
if (informationLabel != null) {
informationLabel.setText(oneLine);
}
}
});
}
/**
* Updates Subtest info to the information label.
*
* The information layout is hard to modify so we need to manage information
* label text
*
* @param text
* New label text
*/
private void updateSubtestInfoText(final String text) {
final String newText = text;
runView.getControl().getDisplay().syncExec(new Runnable() {
public void run() {
// if label exists
if (informationLabel != null) {
// get existing label text
String origText = informationLabel.getText();
// split existing text
String[] strArray = origText.split(lineFeed);
// create new buffer
StringBuffer tmpBuffer = new StringBuffer(strArray.length);
if (strArray.length >= 3) {
// update text
strArray[2] = newText;
// get updated text to buffer
for (int i = 0; i < strArray.length; i++) {
tmpBuffer.append(strArray[i]);
tmpBuffer.append(lineFeed);
}
// set new text to information label
informationLabel.setText(tmpBuffer.toString());
} else {
informationLabel.setText(origText + newText);
}
}
}
});
}
/**
* Updates button states, clears existing project data and updating view.
*/
private void traceStarted() {
// clear view contents
cleanAnalyzeData(project);
clearCallstackViewContent();
traceStartedProjectRef = project;
// change icon and information text
traceAction.setImageDescriptor(Activator
.getImageDescriptor((Constants.BUTTON_STOP)));
traceAction.setText(Constants.ACTION_STOP_TRACE);
traceAction.setToolTipText(Constants.ACTION_STOP_TRACE);
traceActive = true;
String fromTarget = getTraceTarget(traceStartedProjectRef);
updateLabel(fromTarget.length() == 0 ? Constants.INFO_TRACE_START
: String.format(Constants.INFO_TRACE_FROM_TARGET_START,
fromTarget));
// add2UserActionHistory( "Trace started for
// project: "
// +project.getName() +" at "+ Util.getTime() );
// set start and stop subtest visible
startSubtest.setEnabled(true);
stopSubtest.setEnabled(false);
fileOpenMenu.setEnabled(false);
saveFileMenu.setEnabled(false);
cleanAtoolChanges.setEnabled(false);
updateAllocNumber();
}
/**
* Overrided method to capture keyevents.
*
* @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
*/
public void keyPressed(KeyEvent e) {
// C key address(hex)
final int CTRL_C = 0x3;
// key event character
int charValue = e.character;
// c key pressed
boolean cPressed = (charValue == CTRL_C); // This should be enough
// ctrl key pressed
boolean ctrlPressed = (e.stateMask & SWT.CTRL) != 0;
// if ctrl and c key pressed => run copy action
if (ctrlPressed & cPressed) {
// Triggering copy action
copyAction.run();
}
}
/**
* (non-Javadoc)
*
* @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
*/
public void keyReleased(KeyEvent e) {
// This method is overrided
}
/**
* This job parses the .dat file and loads the graph
*
*/
class GraphLoadJob extends Job {
/** Location of file to parse for graph model */
private String datFileLocation;
/**
* Constructor
*
* @param aDatFileLocation
* Location of file to parse for graph model
*/
public GraphLoadJob(String aDatFileLocation) {
super(Constants.GRAPH_LOAD_JOB_TITLE);
this.datFileLocation = aDatFileLocation;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask(Constants.GRAPH_GENERATING_PROG_TITLE,
IProgressMonitor.UNKNOWN);
try {
ReadFile fileReader = new ReadFile();
boolean success = fileReader.readFile(datFileLocation);
if (success) {
AbstractList<ProcessInfo> processes = fileReader
.getStatistic();
IMemoryActivityModel model = new AnalyzeFactory()
.createModel(processes.size() == 0);
if (processes.size() > 0) {
model.setDeferredCallstackReading(fileReader
.hasDeferredCallstacks());
if (model.isDeferredCallstackReading()) {
DeferredCallstackManager callstackManager = new DeferredCallstackManager(
datFileLocation);
callstackManager.setProcesses(processes);
model.setCallstackManager(callstackManager);
} else {
model
.setCallstackManager(new SimpleCallstackManager());
}
}
if (!monitor.isCanceled()) {
chart.setInput(project, model);
model.addProcesses(processes);
}
fileReader.finish();
}
} catch (OutOfMemoryError oome) {
Activator
.getDefault()
.logInfo(IStatus.ERROR, IStatus.ERROR,
"Can not allocate enough memory for the memory usage graph model.");
} catch (Exception e) {
Activator.getDefault().log(IStatus.ERROR,
"Error while generating graph model", e);
}
graphLoadJob = null;
return Status.OK_STATUS;
}
}
}