com.nokia.s60tools.analyzetool.ui.MainView.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.s60tools.analyzetool.ui.MainView.java

Source

/*
 * 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;
        }
    }
}