com.kdmanalytics.toif.ui.views.FindingView.java Source code

Java tutorial

Introduction

Here is the source code for com.kdmanalytics.toif.ui.views.FindingView.java

Source

/*******************************************************************************
 * Copyright (c) 2016 KDM Analytics, Inc. All rights reserved. This program and
 * the accompanying materials are made available under the terms of the Open
 * Source Initiative OSI - Open Software License v3.0 which accompanies this
 * distribution, and is available at
 * http://www.opensource.org/licenses/osl-3.0.php/
 ******************************************************************************/

package com.kdmanalytics.toif.ui.views;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspace;
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.MultiStatus;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
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.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.ViewPart;

import com.kdmanalytics.etoif.ccr.CoverageClaimGenerator;
import com.kdmanalytics.toif.ui.Activator;
import com.kdmanalytics.toif.ui.common.AdaptorConfiguration;
import com.kdmanalytics.toif.ui.common.FindingEntry;
import com.kdmanalytics.toif.ui.common.FindingGroup;
import com.kdmanalytics.toif.ui.common.IAdaptorConfigurationListener;
import com.kdmanalytics.toif.ui.common.IFindingEntry;
import com.kdmanalytics.toif.ui.internal.filters.AndFilter;
import com.kdmanalytics.toif.ui.internal.filters.ConfiguredVisibilityFilter;
import com.kdmanalytics.toif.ui.internal.filters.ResourceFilter;
import com.kdmanalytics.toif.ui.internal.filters.TermFilter;
import com.kdmanalytics.toif.ui.views.sort.AConfigWeightSortAction;
import com.kdmanalytics.toif.ui.views.sort.AdaptorConfigWeightComparator;
import com.kdmanalytics.toif.ui.views.sort.FindingGroupSortAction;
import com.kdmanalytics.toif.ui.views.sort.FindingViewColumnComparator;

/**
 * This sample class demonstrates how to plug-in a new workbench view. The view shows data obtained
 * from the model. The sample creates a dummy model on the fly, but a real implementation would
 * connect to the model available either in this or another plug-in (e.g. the workspace). The view
 * is connected to the model using a content provider.
 * <p>
 * The view uses a label provider to define how model objects should be presented in the view. Each
 * view can present the same model objects using different labels and icons, if needed.
 * Alternatively, a single label provider can be shared between views in order to ensure that
 * objects of the same type are presented in the same way everywhere.
 * <p>
 */

public class FindingView extends ViewPart {

    /**
     * The ID of the view as specified by the extension.
     */
    public static final String ID = "com.kdmanalytics.toif.views.FindingView";

    /**
     * Time format used to make file names.
     * 
     * Not actually ISO format, since that doesn't work on some file systems
     */
    private DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss");

    /**
     * Track citing time so we can back up citing information on a daily
     * (or new usage) basis. This is used with a session property.
     */
    public static final QualifiedName PROJECT_CITE_DATE = new QualifiedName(Activator.PLUGIN_ID, "citeDate");

    /** The Constant DESCRIPTION_KEY. */
    private static final String DESCRIPTION_KEY = "description";

    /** The Constant EXPORT_KEY. */
    private static final String EXPORT_KEY = "export";

    /** The Constant COVERAGE_KEY. */
    private static final String COVERAGE_KEY = "coverage";

    /** The Constant FILTER_KEY. */
    private static final String FILTER_KEY = "filter";

    /** The Constant SORT_KEY. */
    private static final String SORT_KEY1 = "sort1";

    /** The Constant SORT_KEY. */
    private static final String SORT_KEY2 = "sort2";

    /** The Constant FILTER_KEY. */
    private static final String NOT_WEAKNESS_KEY = "not_weakness";

    /** The Constant FILTER_KEY. */
    private static final String IS_WEAKNESS_KEY = "is_weakness";

    /** The Constant FILTER_KEY. */
    private static final String UNCITE_WEAKNESS_KEY = "uncite_weakness";

    /** The Constant FILTER_KEY. */
    private static final String SET_TRUST_KEY = "set_trust";

    /** The Constant FILTER_KEY. */
    private static final String TRACE_KEY = "trace";

    /** The Constant FILTER_KEY. */
    private static final String MORE_INFO_KEY = "more_info";

    /**
     * Project currently being displayed
     */
    private IProject currentProject;

    private FindingSelectionChangedListener selection = null;

    /**
     * Conent for table
     */
    private FindingContentProvider contentProvider;

    private TreeViewer viewer;

    // Button actions
    private Action aConfigSortActionButton;
    private Action findingGroupSortActionButton;

    private Action aConfigSortAction;
    private Action findingGroupSortAction;

    // Column ordering action
    private SaveColumnOrderAction preserveColumnOrderAction;

    private Action descriptionAction;
    private Action exportAction;
    private Action coverageAction;
    private Action filterAction;
    private Action doubleClickAction;
    private Action notAWeaknessAction;
    private Action isAWeaknessAction;
    private Action unciteWeaknessAction;
    private Action setTrustLevelAction;
    private Action traceAction;
    private Action moreInformationAction;

    /**
     * Label that indicates number of findings.
     */
    private Label label;
    private Label projectLabel;
    private Label filterLabel;

    /**
     * File to save a citing history within
     */
    private IFile saveFile;

    /**
     * selection changed listener. looks for selection of project to reload toif
     * data.
     */
    ISelectionListener selectionListener = new ISelectionListener() {
        public void selectionChanged(IWorkbenchPart part, ISelection sel) {
            if (sel instanceof IStructuredSelection) {
                for (Object object : ((IStructuredSelection) sel).toArray()) {
                    if (object instanceof IAdaptable) {
                        IAdaptable adapt = (IAdaptable) object;
                        object = (IResource) adapt.getAdapter(IResource.class);
                    }

                    // Find out the project for the resource
                    if (object instanceof IResource) {
                        IProject newProject = ((IResource) object).getProject();

                        if (currentProject != newProject) {
                            currentProject = newProject;
                            viewer.setInput(newProject);
                            viewer.refresh();
                            updateDefectCount();
                        }

                        // Bail after the first project is found.
                        return;
                    }
                }
            }
        }
    };

    /**
     * The constructor.
     */
    public FindingView() {
        // Load images
        loadImagesIntoRegistry();

        IWorkspace workspace = ResourcesPlugin.getWorkspace();

        //      // Listen for resource change events
        //      IResourceChangeListener preListener = new IResourceChangeListener()
        //      {
        //         public void resourceChanged(IResourceChangeEvent event)
        //         {
        //            System.err.println("PRE-BUILD:");
        //            IResourceDelta delta = event.getDelta();
        //            update(delta);
        //         }
        //      };
        //      workspace.addResourceChangeListener(preListener, IResourceChangeEvent.PRE_BUILD);

        // Listen for resource change events, specifically post-build events.
        // This will allow us to refresh only once the markers have been created.
        IResourceChangeListener postListener = new IResourceChangeListener() {
            public void resourceChanged(IResourceChangeEvent event) {
                IResourceDelta delta = event.getDelta();
                update(delta);
            }
        };
        workspace.addResourceChangeListener(postListener, IResourceChangeEvent.POST_BUILD);

        // Listen for pertinent project change events that should cause the view contents to change
        IResourceChangeListener projectListener = new IResourceChangeListener() {

            @Override
            public void resourceChanged(IResourceChangeEvent event) {
                if (event == null || event.getDelta() == null)
                    return;
                try {
                    event.getDelta().accept(new IResourceDeltaVisitor() {
                        public boolean visit(IResourceDelta delta) throws CoreException {
                            if (delta.getKind() == IResourceDelta.CHANGED) {
                                final IResource resource = delta.getResource();
                                if (!(resource instanceof IProject))
                                    return true;
                                IResourceDelta[] children = delta.getAffectedChildren();
                                // If the project file was changed then refresh things
                                if (children.length == 1
                                        && children[0].getResource().getName().equals(".project")) {
                                    PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
                                        @Override
                                        public void run() {
                                            clear();
                                        }

                                    });
                                }
                                return false;
                            }
                            return true;
                        }
                    });
                } catch (CoreException e) {
                    e.printStackTrace();
                }
            };
        };

        workspace.addResourceChangeListener(projectListener);

        // Listen for configuration changes and update the view accordingly.
        IAdaptorConfigurationListener configListener = new IAdaptorConfigurationListener() {
            @Override
            public void configChanged() {
                viewer.refresh();
                updateDefectCount();
            }
        };
        AdaptorConfiguration.getAdaptorConfiguration().addConfigurationListsner(configListener);

    }

    /**
     * A clear is called when something dramatic has changed in the project.
     */
    private void clear() {
        Control control = viewer.getControl();
        if (!control.isDisposed()) {
            viewer.getControl().setRedraw(false);
            contentProvider.clear();
            viewer.refresh();
            viewer.getControl().setRedraw(true);
        }
    }

    /** Update data for the specified file(s)
     * 
     * @param delta
     */
    protected void update(final IResourceDelta delta) {
        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
            @Override
            public void run() {
                if (delta != null) {
                    viewer.getControl().setRedraw(false);
                    IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() {
                        /*
                         * (non-Javadoc)
                         * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
                         */
                        public boolean visit(IResourceDelta delta) throws CoreException {
                            IResource resource = delta.getResource();
                            if (resource instanceof IFile) {
                                FindingContentProvider content = (FindingContentProvider) viewer
                                        .getContentProvider();
                                content.update(viewer, (IFile) resource);
                            }
                            return true;
                        }
                    };

                    try {
                        delta.accept(visitor);
                    } catch (CoreException e) {
                        e.printStackTrace();
                    }
                    viewer.getControl().setRedraw(true);
                }
                updateDefectCount();
            }
        });

    }

    /**
     * Load images.
     */
    private void loadImagesIntoRegistry() {
        final ImageRegistry imgReg = Activator.getDefault().getImageRegistry();
        if (imgReg.get(DESCRIPTION_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/flag_purple.png");
            imgReg.put(DESCRIPTION_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(EXPORT_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/table_go.png");
            imgReg.put(EXPORT_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(COVERAGE_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/page_code_go.png");
            imgReg.put(COVERAGE_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(FILTER_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/filter.gif");
            imgReg.put(FILTER_KEY, ImageDescriptor.createFromURL(url));
        }

        if (imgReg.get(SORT_KEY1) == null) {
            final URL url = this.getClass().getResource("/icons/flag_green.png");
            imgReg.put(SORT_KEY1, ImageDescriptor.createFromURL(url));
        }

        if (imgReg.get(SORT_KEY2) == null) {
            final URL url = this.getClass().getResource("/icons/flag_orange.png");
            imgReg.put(SORT_KEY2, ImageDescriptor.createFromURL(url));
        }

        if (imgReg.get(NOT_WEAKNESS_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/tick.png");
            imgReg.put(NOT_WEAKNESS_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(IS_WEAKNESS_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/cross.png");
            imgReg.put(IS_WEAKNESS_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(UNCITE_WEAKNESS_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/bullet_white.png");
            imgReg.put(UNCITE_WEAKNESS_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(SET_TRUST_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/priority.gif");
            imgReg.put(SET_TRUST_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(TRACE_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/timeline_marker.png");
            imgReg.put(TRACE_KEY, ImageDescriptor.createFromURL(url));
        }
        if (imgReg.get(MORE_INFO_KEY) == null) {
            final URL url = this.getClass().getResource("/icons/information.png");
            imgReg.put(MORE_INFO_KEY, ImageDescriptor.createFromURL(url));
        }
    }

    /**
     * This is a callback that will allow us
     * to create the viewer and initialize it.
     */
    public void createPartControl(Composite composite) {
        getSite().getPage().addSelectionListener(selectionListener);

        GridLayout layout = new GridLayout();
        layout.numColumns = 3;
        composite.setLayout(layout);

        createSearchControl(composite);

        viewer = new TreeViewer(composite,
                SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);

        contentProvider = new FindingContentProvider();
        viewer.setContentProvider(contentProvider);

        // Set the default comparator. Selecting columns will change the comparator.
        viewer.setComparator(new AdaptorConfigWeightComparator());

        // Listen to change events so we know what to run actions upon
        selection = new FindingSelectionChangedListener();
        viewer.addSelectionChangedListener(selection);

        // Enable the default filters
        FilterUtility filter = new FilterUtility(this, viewer);
        filter.applyFilters();

        Tree tree = viewer.getTree();
        GridData gridData = new GridData();
        gridData.horizontalAlignment = GridData.FILL;
        gridData.verticalAlignment = GridData.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = true;
        gridData.horizontalSpan = 3;
        tree.setLayoutData(gridData);

        tree.setHeaderVisible(true);
        tree.setLinesVisible(true);
        ColumnViewerToolTipSupport.enableFor(viewer);

        String[] titles = { "File", "Location", "Tool", "SFP", "CWE", "Confidence", "Description" };
        Integer[] bounds = { 200, 100, 200, 70, 90, 50, 900 };

        List<String> headings = new LinkedList<String>();
        for (String heading : titles)
            headings.add(heading);
        List<Integer> boundsList = new LinkedList<Integer>();
        for (Integer i : bounds)
            boundsList.add(i);
        String[] extraHeadings = AdaptorConfiguration.getAdaptorConfiguration().getExtraColumnNames();
        for (String heading : extraHeadings) {
            headings.add(heading);
            boundsList.add(70);
        }
        titles = headings.toArray(new String[headings.size()]);
        bounds = boundsList.toArray(new Integer[boundsList.size()]);

        // Create the columns
        for (int i = 0; i < titles.length; i++) {
            TreeViewerColumn col = createTableViewerColumn(viewer, titles[i], bounds[i], i, true);
            col.setLabelProvider(new FindingStyledLabelProvider());
        }

        viewer.setInput(getViewSite());
        getSite().setSelectionProvider(viewer);

        // Create the help context id for the viewer's control
        PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), "com.kdmanalytics.etoif2.viewer");
        makeActions();
        hookContextMenu();
        hookDoubleClickAction();
        contributeToActionBars();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.ui.part.WorkbenchPart#dispose()
     */
    @Override
    public void dispose() {
        getSite().getPage().removeSelectionListener(selectionListener);
    }

    /**
     * create the search bar control
     * 
     * @param parent
     * @return
     */
    private void createSearchControl(Composite parent) {
        // create a label to display information about the view in.
        final Text text = new Text(parent, SWT.SINGLE | SWT.BORDER);

        GridData gridData = new GridData();
        gridData.horizontalAlignment = GridData.FILL;
        gridData.verticalAlignment = GridData.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = true;
        text.setLayoutData(gridData);

        text.setMessage("Search for Everything...");

        text.addListener(SWT.DefaultSelection, new Listener() {

            @Override
            public void handleEvent(Event event) {
                handleTermFilter(text);
            }
        });

        GridData layoutData = new GridData();
        layoutData.grabExcessHorizontalSpace = true;
        layoutData.horizontalAlignment = GridData.FILL;
        text.setLayoutData(layoutData);

        // Search button
        Button button = new Button(parent, SWT.BORDER);
        gridData = new GridData();
        button.setLayoutData(gridData);

        button.setText("Search");
        button.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                handleTermFilter(text);
            }

        });

        // Clear button
        button = new Button(parent, SWT.BORDER);
        gridData = new GridData();
        button.setLayoutData(gridData);

        button.setText("Clear");
        button.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                handleTermFilterClear(text);
            }

        });

        Composite labelRow = new Composite(parent, SWT.NONE);
        gridData = new GridData();
        gridData.horizontalAlignment = GridData.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.horizontalSpan = 3;
        labelRow.setLayoutData(gridData);
        labelRow.setLayout(new RowLayout());

        // ProjectLabel indicates the currently selected project
        projectLabel = new Label(labelRow, SWT.NONE);
        if (this.currentProject != null)
            projectLabel.setText("[" + currentProject.getName() + "]");
        else
            projectLabel.setText("[No project selected]");

        // Filter label indicates whether a filter is active or not
        filterLabel = new Label(labelRow, SWT.NONE);

        // Label indicates the search results (number of defects)
        label = new Label(labelRow, SWT.NONE);
        label.setText("Number of Defects:");
    }

    /**
     * 
     * @param viewer
     * @param title
     * @param bound
     * @param colNumber
     * @param enableSorting
     * @return
     */
    private TreeViewerColumn createTableViewerColumn(TreeViewer viewer, final String title, final int bound,
            final int colNumber, boolean enableSorting) {
        TreeViewerColumn viewerColumn = new TreeViewerColumn(viewer, SWT.LEFT);
        final TreeColumn column = viewerColumn.getColumn();
        column.setText(title);
        column.setWidth(bound);
        column.setResizable(true);
        column.setMoveable(true);
        if (enableSorting == true) {
            column.addSelectionListener(getSelectionAdapter(viewer, column, colNumber));
        }
        return viewerColumn;
    }

    /**
     * Create a Selection Adapter for the given column and index
     * 
     * @param column
     * @param index
     * @return
     */
    private SelectionAdapter getSelectionAdapter(final TreeViewer viewer2, final TreeColumn column,
            final int index) {
        SelectionAdapter selectionAdaptor = new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                ViewerComparator comparator = viewer2.getComparator();
                if (!(comparator instanceof FindingViewColumnComparator)) {
                    comparator = new FindingViewColumnComparator();
                    viewer2.setComparator(comparator);
                }
                ((FindingViewColumnComparator) comparator).setColumn(index);
                int dir = ((FindingViewColumnComparator) comparator).getDirection();
                viewer2.getTree().setSortDirection(dir);
                viewer2.getTree().setSortColumn(column);
                viewer2.refresh();
            }
        };
        return selectionAdaptor;

    }

    /**
     * 
     */
    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                FindingView.this.fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
        //      getSite().registerContextMenu(menuMgr, viewer);
    }

    /**
     * 
     */
    private void contributeToActionBars() {
        IActionBars bars = getViewSite().getActionBars();
        fillLocalPullDown(bars.getMenuManager());
        fillLocalToolBar(bars.getToolBarManager());
    }

    /**
     * 
     * @param manager
     */
    private void fillLocalPullDown(IMenuManager manager) {
        manager.add(filterAction);

        MenuManager menu1 = new MenuManager("Sort", "sortid");
        menu1.add(aConfigSortAction);
        menu1.add(findingGroupSortAction);
        manager.add(menu1);
        manager.add(preserveColumnOrderAction);
    }

    /**
     * 
     * @param manager
     */
    private void fillContextMenu(IMenuManager manager) {
        manager.add(notAWeaknessAction);
        manager.add(isAWeaknessAction);
        manager.add(unciteWeaknessAction);
        // Remove the setTrustLevel since it should be set by the Adaptor Configuration preferences
        //manager.add(setTrustLevelAction);
        manager.add(traceAction);
        manager.add(moreInformationAction);
    }

    /**
     * 
     * @param manager
     */
    private void fillLocalToolBar(IToolBarManager manager) {
        manager.add(aConfigSortActionButton);
        manager.add(findingGroupSortActionButton);

        manager.add(descriptionAction);
        manager.add(exportAction);
        manager.add(coverageAction);
    }

    /**
     * 
     */
    private void makeActions() {
        final ImageRegistry imgReg = Activator.getDefault().getImageRegistry();

        // Sort Actions
        aConfigSortActionButton = new AConfigWeightSortAction(this, viewer);
        aConfigSortActionButton.setText("User defined sort order");
        aConfigSortActionButton.setToolTipText("User defined sort order");
        aConfigSortActionButton.setImageDescriptor(imgReg.getDescriptor(SORT_KEY1));

        findingGroupSortActionButton = new FindingGroupSortAction(this, viewer);
        findingGroupSortActionButton.setText("Sort by Multiple Findings");
        findingGroupSortActionButton.setToolTipText("Sort by Multiple Findings");
        findingGroupSortActionButton.setImageDescriptor(imgReg.getDescriptor(SORT_KEY2));

        // Export Action
        descriptionAction = new Action() {
            public void run() {
                PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
                    public void run() {
                        IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
                        IWorkbenchPage page = window.getActivePage();
                        try {
                            page.showView(DefectDescriptionView.ID);
                        } catch (PartInitException e) {
                            e.printStackTrace();
                        }
                    }
                });

            }
        };
        descriptionAction.setText("Defect Description");
        descriptionAction.setToolTipText("Defect Description");
        descriptionAction.setImageDescriptor(imgReg.getDescriptor(DESCRIPTION_KEY));

        // Export Action
        exportAction = new Action() {
            public void run() {
                FileDialog dialog = new FileDialog(viewer.getControl().getShell(), SWT.SAVE);
                dialog.setFilterExtensions(new String[] { "*.tsv" });
                String result = dialog.open();
                File file = new File(result);
                try {
                    if (selection.isEmpty()) {
                        MessageDialog.openInformation(viewer.getControl().getShell(), "No selection for export",
                                "Findings must be selected within the view for export.");
                    } else {
                        selection.exportTsv(file);
                    }
                } catch (IOException e) {
                    // build the error message and include the current stack trace
                    MultiStatus status = createMultiStatus(e.getLocalizedMessage(), e);
                    // show error dialog
                    ErrorDialog.openError(viewer.getControl().getShell(), "Error", "This is an error", status);
                }
            }
        };
        exportAction.setText("Export Selection");
        exportAction.setToolTipText("Export Selection");
        exportAction.setImageDescriptor(imgReg.getDescriptor(EXPORT_KEY));

        // Coverage Action
        coverageAction = new Action() {
            public void run() {
                FileDialog dialog = new FileDialog(viewer.getControl().getShell(), SWT.SAVE);
                dialog.setFilterNames(new String[] { "XML Files", "All Files (*.*)" });
                dialog.setFilterExtensions(new String[] { "*.xml", "*.*" });
                dialog.setFilterPath(System.getProperty("user.dir"));
                dialog.setFileName("toif_Coverage.xml");
                final String savePath = dialog.open();

                if (savePath != null) {
                    try {
                        class CcrJob extends Job {

                            public CcrJob() {
                                super("Making Coverage Report...");
                            }

                            public IStatus run(IProgressMonitor monitor) {
                                SubMonitor progress = SubMonitor.convert(monitor);
                                progress.beginTask("Creating Coverage Report...", IProgressMonitor.UNKNOWN);
                                // Make and run the coverage generator on the workspace for now. We probably want to
                                // restrict to the active project?
                                FindingContentProvider contents = (FindingContentProvider) viewer
                                        .getContentProvider();
                                FindingEntry[] findings = contents.getFindingEntries();
                                new CoverageClaimGenerator(findings, new File(savePath), false);
                                return Status.OK_STATUS;
                            }
                        }
                        ;
                        new CcrJob().schedule();

                    } catch (NullPointerException e) {
                        System.err.println("There was a null pointer exception.");
                        e.printStackTrace();
                    }
                }
            }
        };
        coverageAction.setText("Export Coverage");
        coverageAction.setToolTipText("Export Coverage");
        coverageAction.setImageDescriptor(imgReg.getDescriptor(COVERAGE_KEY));

        // Filter Action
        filterAction = new FilterAction(this, viewer);
        filterAction.setText("Filters...");
        filterAction.setImageDescriptor(imgReg.getDescriptor(FILTER_KEY));

        // Sort actions
        aConfigSortAction = new AConfigWeightSortAction(this, viewer);
        aConfigSortAction.setText("User defined");
        aConfigSortAction.setImageDescriptor(imgReg.getDescriptor(SORT_KEY1));

        findingGroupSortAction = new FindingGroupSortAction(this, viewer);
        findingGroupSortAction.setText("Multiple");
        findingGroupSortAction.setImageDescriptor(imgReg.getDescriptor(SORT_KEY2));

        // Column ordering action
        preserveColumnOrderAction = new SaveColumnOrderAction(this, viewer);
        preserveColumnOrderAction.setText("Preserve column order");
        // Restore the column order
        preserveColumnOrderAction.restore();

        // Not a Weakness
        notAWeaknessAction = new Action() {
            public void run() {
                selection.cite(false);
                backupCitings();
            }
        };
        notAWeaknessAction.setText("Not a Weakness");
        notAWeaknessAction.setImageDescriptor(imgReg.getDescriptor(NOT_WEAKNESS_KEY));

        // Not a Weakness
        isAWeaknessAction = new Action() {
            public void run() {
                selection.cite(true);
                backupCitings();
            }
        };
        isAWeaknessAction.setText("Is a Weakness");
        isAWeaknessAction.setImageDescriptor(imgReg.getDescriptor(IS_WEAKNESS_KEY));

        // Uncite Weakness
        unciteWeaknessAction = new Action() {
            public void run() {
                selection.cite(null);
                backupCitings();
            }
        };
        unciteWeaknessAction.setText("Uncite Weakness");
        unciteWeaknessAction.setImageDescriptor(imgReg.getDescriptor(UNCITE_WEAKNESS_KEY));

        // Set trust level
        setTrustLevelAction = new Action() {
            public void run() {
                InputDialog dialog = new InputDialog(viewer.getControl().getShell(), "Trust Level",
                        "Set the trust level", Integer.toString(selection.getTrust()), new IntegerInputValidator());

                int code = dialog.open();
                if (code == InputDialog.OK) {
                    String value = dialog.getValue();

                    // Don't need try/catch. If we get here the value MUST
                    // be an integer.
                    int val = Integer.parseInt(value);
                    selection.setTrust(val);
                }
                backupCitings();
            }
        };
        setTrustLevelAction.setText("Set Trust Level");
        setTrustLevelAction.setImageDescriptor(imgReg.getDescriptor(SET_TRUST_KEY));

        // Set trust level
        traceAction = new Action() {
            public void run() {
                showMessage("Trace executed");
            }
        };
        traceAction.setText("Trace");
        traceAction.setImageDescriptor(imgReg.getDescriptor(TRACE_KEY));
        // Disable trace since no tools support it yet.
        traceAction.setEnabled(false);

        // Set trust level
        moreInformationAction = new Action() {
            public void run() {
                selection.moreInfo();
            }
        };
        moreInformationAction.setText("More Information");
        moreInformationAction.setImageDescriptor(imgReg.getDescriptor(MORE_INFO_KEY));

        // Double click action
        doubleClickAction = new Action() {
            public void run() {
                ISelection selection = viewer.getSelection();
                IFindingEntry finding = (IFindingEntry) ((IStructuredSelection) selection).getFirstElement();
                IFile file = finding.getFile();

                if (!file.exists() || file.getProjectRelativePath().toString().startsWith(".KDM/TOIF")) {
                    MessageDialog.openError(viewer.getControl().getShell(), "Cannot open file",
                            "The file '" + file.getName() + "' is not in the project.");
                } else {
                    IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();

                    try {
                        HashMap<String, Object> map = new HashMap<String, Object>();
                        map.put(IMarker.LINE_NUMBER, finding.getLineNumber());
                        IMarker marker = file.createMarker(IMarker.TEXT);
                        marker.setAttributes(map);
                        IDE.openEditor(page, marker); //3.0 API
                        marker.delete();
                    } catch (CoreException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
    }

    /** If this is the first citing on a project. If it is then save a backup
     * of the current settings.
     *
     * Also saves if the citing is on a different day.
     */
    protected void backupCitings() {
        if (currentProject == null)
            return;

        try {
            Date date = (Date) currentProject.getSessionProperty(PROJECT_CITE_DATE);
            Date now = new Date();
            if (saveFile == null || date == null || !isSameDay(date, now)) {
                IFolder kdm = currentProject.getFolder(".KDM");
                IFolder toif = kdm.getFolder("TOIF");
                IFolder history = toif.getFolder("history");
                if (!history.exists())
                    history.create(true, true, null);
                String name = currentProject.getName() + "." + isoDateFormat.format(now) + ".tsv";
                saveFile = history.getFile(name);
            }

            // Save the findings
            FindingContentProvider contents = (FindingContentProvider) viewer.getContentProvider();
            FindingEntry[] findings = contents.getFindingEntries();
            FindingSelection selection = new FindingSelection(findings, true);

            selection.exportTsv(saveFile.getLocation().toFile());
            currentProject.setSessionProperty(PROJECT_CITE_DATE, now);
        } catch (CoreException | IOException e) {
            e.printStackTrace();
        }

    }

    /** Return true if these dates are on the same day
     * 
     * @param date1
     * @param date2
     * @return
     */
    private boolean isSameDay(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(date1);
        cal2.setTime(date2);
        boolean sameDay = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
                && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
        return sameDay;
    }

    private void hookDoubleClickAction() {
        viewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                doubleClickAction.run();
            }
        });
    }

    private void showMessage(String message) {
        MessageDialog.openInformation(viewer.getControl().getShell(), "Finding View", message);
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    public void setFocus() {
        viewer.getControl().setFocus();
    }

    /**
     * deal with the term filter. apply the term filter data to the current
     * view.
     * 
     * From TOIF ReportView
     * 
     * @param text
     */
    private void handleTermFilter(Text text) {
        String[] terms = text.getText().split("OR");
        if (text.getText().isEmpty()) {
            handleTermFilterClear(text);
        } else {
            FilterUtility filter = new FilterUtility(this, viewer);
            filter.add(new TermFilter(terms));
            filter.applyFilters();
            updateDefectCount();
            text.setMessage("Search for Everything...");
        }
    }

    /** Clear the term filter
     * 
     * @param text
     */
    private void handleTermFilterClear(Text text) {
        FilterUtility filter = new FilterUtility(this, viewer);
        filter.clear();
        filter.applyFilters();

        updateDefectCount();
        text.setMessage("Search for Everything...");
        text.setText("");
    }

    /** From http://www.vogella.com/tutorials/EclipseDialogs/article.html#dialogs_jface_errordialog
     * 
     * @param msg
     * @param t
     * @return
     */
    private static MultiStatus createMultiStatus(String msg, Throwable t) {

        List<Status> childStatuses = new ArrayList<>();
        StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();

        for (StackTraceElement stackTrace : stackTraces) {
            Status status = new Status(IStatus.ERROR, "com.kdmanalytics.toif", stackTrace.toString());
            childStatuses.add(status);
        }

        MultiStatus ms = new MultiStatus("com.kdmanalytics.toif", IStatus.ERROR,
                childStatuses.toArray(new Status[] {}), t.toString(), t);
        return ms;
    }

    /** Set the text for the label.
     * 
     * @param text
     */
    public void setLabel(final String text) {
        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {

            @Override
            public void run() {
                // Setup the project label with the project name
                if (currentProject != null && currentProject.isOpen()) {
                    projectLabel.setText("[" + currentProject.getName() + "]");
                } else {
                    projectLabel.setText("[No project selected]");
                }

                // Indicate if there are any filters active
                // Check to see if ConfiguredVisibilityFilter has anything set
                boolean hasEnabledFilter = false;
                ViewerFilter[] filters = viewer.getFilters();
                if (filters != null) {
                    for (ViewerFilter filter : filters) {
                        if (filter instanceof AndFilter) {
                            // The "AndFilter" contains many child filters
                            ViewerFilter[] children = ((AndFilter) filter).getFilters();
                            for (ViewerFilter child : children) {
                                // Check to see if ConfiguredVisibilityFilter has anything set
                                if (child instanceof ConfiguredVisibilityFilter) {
                                    if (((ConfiguredVisibilityFilter) child).size() > 0) {
                                        hasEnabledFilter = true;
                                        break;
                                    }
                                } else {
                                    hasEnabledFilter = true;
                                    break;
                                }
                            }
                        } else {
                            hasEnabledFilter = true;
                        }
                        // If there is already one enabled filter found, then that is enough
                        if (hasEnabledFilter) {
                            break;
                        }
                    }
                }
                if (!hasEnabledFilter) {
                    filterLabel.setText("");
                } else {
                    filterLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED));
                    filterLabel.setText("(Filter(s) active)");
                }

                // Write the count label
                String useText = text;
                if (currentProject != null && currentProject.isOpen()) {
                    try {
                        if (currentProject.getPersistentProperty(
                                com.kdmanalytics.toif.ui.common.Activator.PROJECT_INCONSISTENT) != null) {
                            useText = "[Inconsistent] " + text;
                            label.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED));
                        } else {
                            label.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
                        }
                    } catch (CoreException e) {
                        e.printStackTrace();
                    }
                }

                label.setText(useText);

                // Layout the labels cleanly
                label.getParent().layout();
            }
        });
    }

    /**
     * update the defect counter. this calculates what to display in the status
     * text.
     */
    public void updateDefectCount() {
        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {

            @Override
            public void run() {
                //                final int totalEntries = contentProvider.getEntries().length;
                //                final int visibleEntries = viewer.getTree().getItemCount();

                final int totalEntries = contentProvider.getFindingEntries().length;

                // Count the children
                int visibleEntries = 0;
                TreeItem[] items = viewer.getTree().getItems();
                for (TreeItem item : items) {
                    Object object = item.getData();
                    if (object instanceof FindingGroup) {
                        visibleEntries += ((FindingGroup) object).size();
                    } else {
                        visibleEntries++;
                    }
                }

                setLabel("Number of Defects: " + visibleEntries + " (" + (totalEntries - visibleEntries)
                        + " filtered from view)");
            }
        });
    }

    /**
     * Citing data or other information may have changed, refresh the view
     */
    public void refresh() {
        this.viewer.refresh();
    }

    /** Add a new filter to the FindingView
     * 
     * @param resources
     */
    public void setResourceFilter(List<IResource> resources) {
        ViewerFilter[] filters = viewer.getFilters();
        List<ViewerFilter> keep = new LinkedList<ViewerFilter>();
        for (ViewerFilter filter : filters) {
            if (!(filter instanceof ResourceFilter)) {
                keep.add(filter);
            }
        }
        viewer.setFilters(keep.toArray(new ViewerFilter[keep.size()]));

        if (resources == null)
            return;
        if (resources.isEmpty())
            return;
        Set<IFile> selectedFiles = new HashSet<IFile>();
        for (IResource resource : resources) {
            if (resource instanceof IProject)
                return;
            addFiles(selectedFiles, resource);
        }

        FilterUtility filter = new FilterUtility(this, viewer);
        filter.add(new ResourceFilter(selectedFiles));
        filter.applyFilters();

        updateDefectCount();
    }

    /** Add all files recursively to the provided filter set
     * 
     * @param selectedFiles
     * @param resource
     */
    private void addFiles(Set<IFile> selectedFiles, IResource resource) {
        if (resource != null) {
            if (resource instanceof IFile) {
                selectedFiles.add((IFile) resource);
            } else if (resource instanceof IContainer) {
                try {
                    IResource[] children = ((IContainer) resource).members();
                    if (children != null) {
                        for (IResource child : children) {
                            addFiles(selectedFiles, child);
                        }
                    }
                } catch (CoreException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}