com.nokia.s60tools.crashanalyser.ui.views.MainView.java Source code

Java tutorial

Introduction

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

Source

/*
* Copyright (c) 2008 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:
*
*/

package com.nokia.s60tools.crashanalyser.ui.views;

import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.*;
import org.eclipse.ui.part.*;
import org.eclipse.swt.dnd.*;

import com.nokia.s60tools.ui.actions.OpenPreferencePageAction;
import com.nokia.s60tools.util.resource.*;
import com.nokia.s60tools.crashanalyser.model.*;
import com.nokia.s60tools.crashanalyser.plugin.*;
import com.nokia.s60tools.crashanalyser.resources.*;
import com.nokia.s60tools.crashanalyser.files.*;
import com.nokia.s60tools.crashanalyser.ui.preferences.CrashAnalyserPreferences;
import com.nokia.s60tools.crashanalyser.ui.wizards.*;
import com.nokia.s60tools.crashanalyser.ui.dialogs.*;
import com.nokia.s60tools.crashanalyser.data.*;
import com.nokia.s60tools.crashanalyser.interfaces.*;

import java.io.*;
import java.util.*;

/**
 * Crash Analyser's main view class. Shows Crash files in a table. 
 * 
 * 
 */
public class MainView extends ViewPart implements IDecodingObserver, IErrorLibraryObserver, INewCrashFilesObserver,
        ISelectionChangedListener, DropTargetListener {

    /**
     * We can get view ID at runtime once the view is instantiated, but we
     * also need static access to ID in order to be able to invoke the view.
     */
    public static final String ID = "com.nokia.s60tools.crashanalyser.ui.views.MainView"; //$NON-NLS-1$
    //private TableViewer tableViewerCrashFiles;
    private TreeViewer treeViewerCrashFiles;
    /**
     * Open the preferences
     */
    private Action mainMenuActionOpenPreferences;

    private Action actionDoubleClick;
    private Action actionOpenWizard;
    private Action actionDecode;
    private Action actionDeleteFiles;
    private Action actionPanicLibrary;
    private Action actionExportToHtml;
    private Action actionExportToXml;
    private Action actionExportAsHtml;
    private Action actionExportAsXml;
    private Action actionExportAll;
    private String errorMessage = "";
    private Browser browserPanicDescription;
    private MainViewContentProvider contentProvider = null;
    private ErrorLibrary errorLibrary = null;
    private boolean mainViewLoaded = false;
    private boolean showWizard = false;
    private boolean wizardRunning = false;
    private static SummaryFile summaryFileFromTrace = null;
    private CrashAnalyserFile fileToBeShown = null;
    private CrashAnalyserWizard wizard = null;

    public void selectionChanged(SelectionChangedEvent arg0) {
        ISelection selection = treeViewerCrashFiles.getSelection();

        // no files selected, don't show description
        if (selection == null || selection.isEmpty()) {
            browserPanicDescription.setText("");
            actionDecode.setEnabled(false);
            actionDeleteFiles.setEnabled(false);
            return;
        }

        @SuppressWarnings("unchecked")
        Iterator<CrashFileBundle> i = ((IStructuredSelection) selection).iterator();
        while (i.hasNext()) {
            CrashFileBundle cFileBundle = i.next();
            // multiple files selected, don't show description
            if (i.hasNext()) {
                browserPanicDescription.setText("");
                break;
                // only one selected file, show description
            } else {
                browserPanicDescription.setText(HtmlFormatter.formatHtmlStyle(browserPanicDescription.getFont(),
                        cFileBundle.getDescription(true)));
            }
        }
        actionDecode.setEnabled(true);
        actionDeleteFiles.setEnabled(true);
    }

    /**
     * Error library calls this method when it's ready to be used (i.e.
     * it has finished reading in all errors & panics from xml files)
     */
    public void errorLibraryReady() {
        contentProvider.setErrorLibrary(errorLibrary);
        actionPanicLibrary.setEnabled(true);
        refreshView();
    }

    /**
     * MainView gets notified by this method to refresh the crash files table
     */
    public void crashFilesUpdated() {
        mainViewLoaded = true;
        actionOpenWizard.setEnabled(true);
        mainMenuActionOpenPreferences.setEnabled(true);
        refreshView();
        if (showWizard) {
            showWizard = false;
            showWizardIfNoFiles();
        }
    }

    /**
     * The constructor.
     */
    public MainView() {
        // no implementation needed
    }

    /**
     * This is a callback that will allow us
     * to create the viewer and initialize it.
     */
    public void createPartControl(Composite parent) {
        SashForm sashFormMain = new SashForm(parent, SWT.HORIZONTAL);
        //createCrashFilesListViewTableViewer(sashFormMain);
        createCrashFilesListViewTreeViewer(sashFormMain);
        createPanicsViewer(sashFormMain);
        sashFormMain.setWeights(new int[] { 2, 1 });

        makeActions();
        hookContextMenu();
        hookDoubleClickAction();
        contributeToActionBars();

        actionOpenWizard.setEnabled(false);
        mainMenuActionOpenPreferences.setEnabled(false);
        actionDecode.setEnabled(false);
        actionPanicLibrary.setEnabled(false);
        errorLibrary = ErrorLibrary.getInstance(this);

        try {
            PlatformUI.getWorkbench().getHelpSystem().setHelp(treeViewerCrashFiles.getControl(),
                    HelpContextIDs.CRASH_ANALYSER_HELP_MAIN_VIEW);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Starts Crash Analyser wizard if there are no decoded Crash 
     * files in the MainView table.
     *
     */
    public void showWizardIfNoFiles() {
        Runnable showWizardRunnable = new Runnable() {
            public void run() {
                try {
                    if (mainViewLoaded) {
                        CrashFileBundle cFile = (CrashFileBundle) treeViewerCrashFiles.getTree().getItem(0)
                                .getData();
                        if (cFile.isEmpty()) {
                            showWizard();
                        }
                    } else {
                        showWizard = true;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        Display.getDefault().asyncExec(showWizardRunnable);

    }

    /**
     * Starts Crash Analyser wizard asynchronously.
     *
     */
    public void showWizard() {
        showWizard(null);
    }

    /**
     * Starts Crash Analyser wizard asynchronously.
     * @param filesToBeDecoded list of files which needs to be decoded with wizard, null if wizard should
     * be started from the beginning.
     *
     */
    public void showWizard(List<CrashFileBundle> filesToBeDecoded) {
        wizard = new CrashAnalyserWizard(filesToBeDecoded, errorLibrary);
        openWizard();
    }

    public void showWizard(String prefilledFileOrFolder, String[] filesToBeShown) {
        wizard = new CrashAnalyserWizard(prefilledFileOrFolder, filesToBeShown, errorLibrary);
        openWizard();
    }

    void openWizard() {
        Runnable showWizardRunnable = new Runnable() {
            public void run() {
                WizardDialog wizDialog;
                wizDialog = new WizardDialog(getViewSite().getShell(), wizard);
                wizDialog.create();
                wizDialog.getShell().setSize(500, 650);
                wizDialog.addPageChangedListener(wizard);
                wizDialog.open();
            }
        };

        Display.getDefault().asyncExec(showWizardRunnable);
    }

    /**
     * Creates the MainView table which is used for showing crash files 
     */
    private void createCrashFilesListViewTreeViewer(Composite parent) {
        SashForm sashFormCrashFiles = new SashForm(parent, SWT.VERTICAL);

        Tree tree = new Tree(sashFormCrashFiles, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);

        tree.setHeaderVisible(true);
        TreeColumn column1 = new TreeColumn(tree, SWT.LEFT);
        column1.setText("Time");
        column1.setWidth(150);

        TreeColumn column2 = new TreeColumn(tree, SWT.LEFT);
        column2.setText("Thread");
        column2.setWidth(250);

        TreeColumn column3 = new TreeColumn(tree, SWT.LEFT);
        column3.setText("Panic Category");
        column3.setWidth(90);

        TreeColumn column4 = new TreeColumn(tree, SWT.LEFT);
        column4.setText("Panic Code");
        column4.setWidth(70);

        TreeColumn column5 = new TreeColumn(tree, SWT.LEFT);
        column5.setText("Crash File");
        column5.setWidth(690);

        TreeViewer treeViewer = new TreeViewer(tree);
        treeViewer.addDropSupport(DND.DROP_COPY, new Transfer[] { FileTransfer.getInstance() }, this);

        contentProvider = new MainViewContentProvider(this);
        treeViewer.setContentProvider(contentProvider);
        treeViewer.setLabelProvider(new MainViewLabelProvider());
        treeViewer.setSorter(new ViewerSorter());
        treeViewer.setInput(getViewSite());
        treeViewer.addSelectionChangedListener(this);
        treeViewer.expandAll();
        treeViewerCrashFiles = treeViewer;
    }

    /**
     * Creates the right side view of the MainView. Contains a browser which
     * is used for showing information about a selected file in MainView table. 
     */
    private void createPanicsViewer(Composite parent) {
        SashForm sashFormPanics = new SashForm(parent, SWT.HORIZONTAL);

        SashForm sashFormPanicLookup = new SashForm(sashFormPanics, SWT.VERTICAL);

        Composite composite = new Composite(sashFormPanicLookup, SWT.NONE);

        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 1;
        composite.setLayout(gridLayout);

        browserPanicDescription = new Browser(composite, SWT.BORDER);
        browserPanicDescription.setLayoutData(new GridData(GridData.FILL_BOTH));
    }

    /**
     * Initialize double-click action
     */
    private void hookDoubleClickAction() {
        treeViewerCrashFiles.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                actionDoubleClick.run();
            }
        });
    }

    /**
     * Initialize context menu
     */
    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                MainView.this.fillContextMenu(manager);

            }
        });
        Menu menu = menuMgr.createContextMenu(treeViewerCrashFiles.getControl());
        treeViewerCrashFiles.getControl().setMenu(menu);
        getSite().registerContextMenu(menuMgr, treeViewerCrashFiles);
    }

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

    /**
     * Fill pull down menu
     */
    private void fillLocalPullDown(IMenuManager manager) {
        manager.add(actionOpenWizard);
        manager.add(mainMenuActionOpenPreferences);
        manager.add(actionDecode);
        manager.add(actionDeleteFiles);
        manager.add(actionPanicLibrary);
        MenuManager exportMenu = getExportMenu(true);
        if (exportMenu != null)
            manager.add(exportMenu);
    }

    /**
     * Fills context menu
     */
    private void fillContextMenu(IMenuManager manager) {
        manager.add(actionDecode);
        manager.add(actionDeleteFiles);
        MenuManager exportMenu = getExportMenu(false);
        if (exportMenu != null)
            manager.add(exportMenu);
    }

    /**
     * Fills tool bar
     */
    private void fillLocalToolBar(IToolBarManager manager) {
        manager.add(actionOpenWizard);
        manager.add(mainMenuActionOpenPreferences);
        manager.add(actionDecode);
        manager.add(actionDeleteFiles);
        manager.add(actionPanicLibrary);
    }

    public void dispose() {
        EditorHandler.closeAllEditors();
    }

    /**
     * Checks based on which files are selected in MainView table, that
     * can Export sub-menu be shown.
     * @return Export menu if it can be show, null if it can't
     */
    private MenuManager getExportMenu(boolean showAlways) {
        MenuManager subMenuExport = new MenuManager("Export");

        ISelection selection = treeViewerCrashFiles.getSelection();
        // if no files are selected, don't show export menu
        if (!showAlways && (selection == null || selection.isEmpty()))
            return null;

        boolean allFilesContainsXml = true;
        boolean itemsAdded = false;

        // go through all selected files
        @SuppressWarnings("unchecked")
        Iterator<CrashFileBundle> i = ((IStructuredSelection) selection).iterator();
        while (i.hasNext()) {
            CrashFileBundle cFileBundle = i.next();

            // if only one item selected, allow export to html and xml if it contains xml file
            if (((IStructuredSelection) selection).size() == 1 && cFileBundle.hasXml()) {
                subMenuExport.add(actionExportToHtml);
                subMenuExport.add(actionExportToXml);
                itemsAdded = true;
            }

            if (!cFileBundle.hasFiles())
                allFilesContainsXml = false;

            // do not show Export menu if "empty file" or emulator panic is selected
            if (cFileBundle.isEmpty() || cFileBundle.isEmulatorPanic())
                return null;
        }

        if (showAlways && !itemsAdded) {
            subMenuExport.add(actionExportToHtml);
            subMenuExport.add(actionExportToXml);
        }

        // if all selected files contains xml file, these actions can be added
        if (allFilesContainsXml || showAlways) {
            subMenuExport.add(actionExportAsHtml);
            subMenuExport.add(actionExportAsXml);
        }

        // export all can always be added, since they will export
        // all files which are available.
        subMenuExport.add(actionExportAll);

        return subMenuExport;
    }

    /**
     * Make all actions (buttons, double-click)
     */
    private void makeActions() {
        mainMenuActionOpenPreferences = new OpenPreferencePageAction(CrashAnalyserPreferences.PAGE_ID, null, null);

        makeDeleteFilesAction();
        makeOpenWizardAction();
        makeOpenPanicLibraryAction();
        makeExportToHtml();
        makeExportToXml();
        makeExportAllAction();
        makeExportAsHtmlAction();
        makeExportAsXmlAction();
        makeDoubleClickAction();
        makeDecodeFilesAction();
    }

    /**
     * Double-click action
     */
    private void makeDoubleClickAction() {
        // when table item is double-clicked
        actionDoubleClick = new Action() {
            public void run() {
                try {
                    if (wizardRunning)
                        return;
                    ISelection selection = treeViewerCrashFiles.getSelection();
                    Object obj = ((IStructuredSelection) selection).getFirstElement();
                    CrashFileBundle cFile = (CrashFileBundle) obj;
                    // if empty file is double-clicked, open wizard
                    if (cFile.isEmpty()) {
                        showWizard();
                        // Crash file (not empty file) is double-clicked
                    } else {
                        // fully decoded
                        if (cFile.isFullyDecoded())
                            EditorHandler.openCrashAnalyserEditor(cFile.getCrashFile());
                        // partially decoded
                        else if (cFile.isPartiallyDecoded())
                            EditorHandler.openCrashAnalyserEditor(cFile.getSummaryFile());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }

    /**
     * Export selected file to html file
     */
    private void makeExportToHtml() {
        actionExportToHtml = new Action() {
            public void run() {
                ISelection selection = treeViewerCrashFiles.getSelection();
                FileExportManager.ExportSelectedFileToHtml(selection, getShell());
            }
        };
        actionExportToHtml.setText("to HTML File");
    }

    /**
     * Export selected file to .xml or .crashxml
     */
    private void makeExportToXml() {
        actionExportToXml = new Action() {
            public void run() {
                ISelection selection = treeViewerCrashFiles.getSelection();
                FileExportManager.ExportSelectedFileToXml(selection, getShell());
            }
        };
        actionExportToXml.setText("to XML File");
    }

    /**
     * Export to Zip as Xml
     */
    private void makeExportAsXmlAction() {
        actionExportAsXml = new Action() {
            public void run() {
                ISelection selection = treeViewerCrashFiles.getSelection();
                FileExportManager.ExportSelectedFilesAsXmlToZip(selection, getShell());
            }
        };
        actionExportAsXml.setText("to Zip as XML");
    }

    /**
     * Export to Zip as Html
     */
    private void makeExportAsHtmlAction() {
        actionExportAsHtml = new Action() {
            public void run() {
                ISelection selection = treeViewerCrashFiles.getSelection();
                FileExportManager.ExportSelectedFilesAsHtmlToZip(selection, getShell());
            }
        };
        actionExportAsHtml.setText("to Zip as HTML");
    }

    /**
     * Export all formats to zip
     */
    private void makeExportAllAction() {
        actionExportAll = new Action() {
            public void run() {
                ISelection selection = treeViewerCrashFiles.getSelection();
                FileExportManager.ExportSelectedFilesToZipInAllFormats(selection, getShell());
            }
        };
        actionExportAll.setText("All Formats to Zip");
    }

    /**
     * Open Error Library button
     */
    private void makeOpenPanicLibraryAction() {
        actionPanicLibrary = new Action() {
            public void run() {
                ErrorLibraryDialog dlg = new ErrorLibraryDialog(treeViewerCrashFiles.getControl().getShell(),
                        errorLibrary);
                dlg.open();
            }
        };
        actionPanicLibrary.setText("Open Error Library...");
        actionPanicLibrary.setToolTipText("Open Error Library Window");
        actionPanicLibrary.setImageDescriptor(ImageResourceManager.getImageDescriptor(ImageKeys.ERROR_LIBRARY));
    }

    /**
     * Import Files button
     */
    private void makeOpenWizardAction() {
        // Open wizard button
        actionOpenWizard = new Action() {
            public void run() {
                showWizard();
            }
        };
        actionOpenWizard.setText("Import Files...");
        actionOpenWizard.setToolTipText("Open File Import Wizard");
        actionOpenWizard.setImageDescriptor(ImageResourceManager.getImageDescriptor(ImageKeys.IMG_APP_ICON));
    }

    /**
     * Starts decoding process for the given file by opening the wizard for given file.
     * @param f file to be decoded
     */
    public void decodeFile(SummaryFile f) {
        int sep = f.getFilePath().lastIndexOf(File.separator);
        CrashFileBundle cfb = new CrashFileBundle(f.getFilePath().substring(0, sep), errorLibrary);
        List<CrashFileBundle> files = new ArrayList<CrashFileBundle>();
        files.add(cfb);
        EditorHandler.closeEditors(files);
        showWizard(files);
    }

    /**
     * Decode files button
     */
    private void makeDecodeFilesAction() {
        actionDecode = new Action() {
            public void run() {
                ISelection selection = treeViewerCrashFiles.getSelection();
                // if nothing is selected, just ignore button press
                if (selection == null || selection.isEmpty())
                    return;

                String romId = "";
                // go through all files and check that they can be re-decoded
                List<CrashFileBundle> files = new ArrayList<CrashFileBundle>();
                @SuppressWarnings("unchecked")
                Iterator i = ((IStructuredSelection) selection).iterator();
                while (i.hasNext()) {
                    CrashFileBundle cFileBundle = (CrashFileBundle) i.next();
                    UndecodedFile udf = cFileBundle.getUndecodedFile();
                    // must have original binaries to be able to re-decode
                    if (udf == null) {
                        errorMessage = "All selected files do not have original binaries available. Cannot Decode.";
                        showErrorMessage();
                        return;
                    }

                    // only mobilecrash files can be re-decoded (e.g. D_EXC files can't)
                    if (!udf.getFileName().toLowerCase()
                            .endsWith("." + CrashAnalyserFile.MOBILECRASH_FILE_EXTENSION)
                            && !udf.getFileName().toLowerCase().endsWith("." + CrashAnalyserFile.TRACE_EXTENSION)) {
                        errorMessage = "Only MobileCrash files can be Decoded.";
                        showErrorMessage();
                        return;
                    }

                    // rom id hasn't yet been read
                    if ("".equals(romId)) {
                        romId = cFileBundle.getRomId();
                        // rom ids of selected files must match
                    } else if (!romId.equalsIgnoreCase(cFileBundle.getRomId())) {
                        errorMessage = "Select only files which have same ROM IDs";
                        showErrorMessage();
                        return;
                    }

                    files.add(cFileBundle);
                }

                if (!files.isEmpty()) {
                    EditorHandler.closeEditors(files);
                    showWizard(files);
                }
            }
        };
        actionDecode.setText("Decode Files...");
        actionDecode.setToolTipText("Decode Selected Files");
        actionDecode.setImageDescriptor(ImageResourceManager.getImageDescriptor(ImageKeys.DECODE_FILES));
        actionDecode.setEnabled(false);
    }

    /**
     * Delete Files button
     */
    private void makeDeleteFilesAction() {
        // Delete file button
        actionDeleteFiles = new Action() {
            public void run() {
                ISelection selection = treeViewerCrashFiles.getSelection();
                if (selection == null || selection.isEmpty())
                    return;

                // Confirm file delete
                MessageBox messageBox = new MessageBox(treeViewerCrashFiles.getControl().getShell(),
                        SWT.ICON_QUESTION | SWT.YES | SWT.NO);
                messageBox.setText("Crash Analyser - Remove Files");
                messageBox.setMessage("Are you sure you want to remove selected files?");
                int buttonID = messageBox.open();
                if (buttonID == SWT.YES) {
                    // go through all selected files and remove them
                    List<CrashFileBundle> closeFiles = new ArrayList<CrashFileBundle>();
                    @SuppressWarnings("unchecked")
                    Iterator<CrashFileBundle> i = ((IStructuredSelection) selection).iterator();
                    while (i.hasNext()) {
                        CrashFileBundle cFileBundle = i.next();
                        if (!cFileBundle.isEmpty()) {
                            cFileBundle.delete();
                            closeFiles.add(cFileBundle);
                        }
                    }
                    EditorHandler.closeEditors(closeFiles);
                    contentProvider.refresh();
                }

                // All items were removed, add empty item
                if (treeViewerCrashFiles.getTree().getItemCount() == 0) {//.getTable().getItemCount() == 0) {
                    CrashFileBundle empty = new CrashFileBundle(true);
                    treeViewerCrashFiles.add(empty, null);
                }
            }
        };
        actionDeleteFiles.setText("Remove Files");
        actionDeleteFiles.setToolTipText("Remove Selected Files");
        actionDeleteFiles.setImageDescriptor(
                PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
        actionDeleteFiles.setEnabled(false);
    }

    /**
     * Shows a message box with given message
     * @param message
     */
    private void showMessage(String message) {
        MessageDialog.openInformation(treeViewerCrashFiles.getControl().getShell(), "Crash Analyser", message);
    }

    /**
     * Shows an error message asynchronously.
     *
     */
    private void showErrorMessage() {
        Runnable showErrorMessageRunnable = new Runnable() {
            public void run() {
                MessageDialog.openError(treeViewerCrashFiles.getControl().getShell(), "Crash Analyser",
                        errorMessage);
                errorMessage = ""; //$NON-NLS-1$
            }
        };

        // Has to be done in its own thread
        // in order not to cause invalid thread access
        Display.getDefault().asyncExec(showErrorMessageRunnable);
    }

    /**
     * Returns a shell
     * @return a shell
     */
    private Shell getShell() {
        return treeViewerCrashFiles.getControl().getShell();
    }

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

    /**
     * When wizard is finished, wizard passes decoder engine to MainView so that 
     * MainView can start decoding process and register itself as the progress listener.
     * @param decoder decoder engine
     */
    public void startDecoding(DecoderEngine decoder) {
        disableUIForImport(true);
        try {
            decoder.decode(this);
        } catch (Exception e) {
            disableUIForImport(false);
            showMessage("Processing Failed: " + e.getMessage());
            setMainViewVisible();
        }
    }

    /**
     * While import is in progess, some actions should be disabled. This method
     * enables/disables necessary actions after/before import.
     * @param disable
     */
    void disableUIForImport(boolean disable) {
        actionDecode.setEnabled(!disable);
        actionOpenWizard.setEnabled(!disable);
        mainMenuActionOpenPreferences.setEnabled(!disable);
        actionDeleteFiles.setEnabled(!disable);
        wizardRunning = disable;
    }

    /**
     * Makes Crash Analyser view visible asynchronously.
     *
     */
    private void setMainViewVisible() {
        Runnable decodingFinishedRunnable = new Runnable() {
            public void run() {
                updateView();
                if (fileToBeShown != null) {
                    if (fileToBeShown instanceof CrashFile) {
                        EditorHandler.openCrashAnalyserEditor((CrashFile) fileToBeShown);
                    } else if (fileToBeShown instanceof SummaryFile) {
                        EditorHandler.openCrashAnalyserEditor((SummaryFile) fileToBeShown);
                    }
                    fileToBeShown = null;
                }
            }
        };

        // Has to be done in its own thread
        // in order not to cause invalid thread access
        Display.getDefault().asyncExec(decodingFinishedRunnable);
    }

    /**
     * Refreshes view asynchronously.
     */
    private void refreshView() {
        Runnable refreshRunnable = new Runnable() {
            public void run() {
                treeViewerCrashFiles.refresh();
            }
        };

        // Has to be done in its own thread
        // in order not to cause invalid thread access
        Display.getDefault().asyncExec(refreshRunnable);
    }

    /**
     * Reloads Crash files to table
     *
     */
    private void updateView() {
        try {
            getViewSite().getPage().showView(MainView.ID);
            treeViewerCrashFiles.refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Used by Decoder Engine to inform when decoding is finished.
     * @param error error message if something went wrong with decoding. Empty if no error occurred
     */
    public void decodingFinished(String error, CrashAnalyserFile caFile) {
        disableUIForImport(false);
        // no errors while decoding
        if ("".equals(error)) { //$NON-NLS-1$

            contentProvider.refresh();
            setMainViewVisible();
            fileToBeShown = caFile;
            // there were errors in decoding process
        } else {
            errorMessage = error;
            showErrorMessage();
            contentProvider.refresh();
        }
    }

    /**
     * Refreshes table
     */
    public void refresh() {
        contentProvider.refresh();
        treeViewerCrashFiles.refresh();
    }

    public void dragEnter(DropTargetEvent event) {
        event.detail = DND.DROP_COPY;
    }

    public void dragLeave(DropTargetEvent event) {
        // Nothing to be done
    }

    public void dragOperationChanged(DropTargetEvent event) {
        // Nothing to be done
    }

    public void dragOver(DropTargetEvent event) {
        event.feedback = DND.FEEDBACK_NONE;
    }

    public void drop(DropTargetEvent event) {
        // we accept only file drops
        if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
            if (event.data != null) {
                String[] files = (String[]) event.data;
                executeDrop(files);
            }
        }
    }

    public void dropAccept(DropTargetEvent event) {
        // Nothing to be done
    }

    /**
     * Executes drop functionality when files are drag&dropped to main view.
     * Checks if supported files where dropped and starts wizard accordingly.
     * @param files drag&dropped files (paths)
     */
    void executeDrop(String[] files) {
        // just one (supported) file dropped
        if (files.length == 1 && DecoderEngine.isFileValidCrashFile(files[0])) {
            showWizard(files[0], files);
            // multiple files dropped
        } else if (files.length > 1) {
            String path = "";
            // go through all dropped files, and check that they are from same folder
            // (wizard doesn't know how to handle multiple files from multiple locations)
            for (int i = 0; i < files.length; i++) {
                if (DecoderEngine.isFileValidCrashFile(files[i])) {
                    if ("".equals(path)) {
                        path = FileOperations.getFolder(files[i]);
                    } else if (!FileOperations.getFolder(files[i]).equalsIgnoreCase(path)) {
                        showMessage("Multiple files from different folders are not supported");
                        break;
                    }
                } else {
                    showMessage("Unsupported file type");
                    break;
                }
            }
            showWizard(path, files);
        } else {
            showMessage("Unsupported file type");
        }
    }

    /**
     * Opens MainView if it is not open. Can be called from a non-UI thread.
     */
    public static void showOrRefresh() {

        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
            public void run() {
                MainView mv = showAndReturnYourself(true);
                mv.refresh();
            }
        });
    }

    /**
     * Opens MainView if it is not open. Can be called from a non-UI thread.
     */
    public static void showOrRefreshAndOpenFile(SummaryFile summaryFile) {
        MainView.summaryFileFromTrace = summaryFile;
        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
            public void run() {
                MainView mv = showAndReturnYourself(true);
                mv.refresh();
                EditorHandler.openCrashAnalyserEditor(summaryFileFromTrace);
            }
        });
    }

    /**
     * Makes main view visible and returns an instance of itself. Can be called from
     * an UI thread only.
     * @return instance of main view
     */
    public static MainView showAndReturnYourself() {
        return showAndReturnYourself(false);
    }

    /**
     * Makes main view visible and returns an instance of itself. Can be called from
     * an UI thread only.
     * @return instance of main view
     */
    public static MainView showAndReturnYourself(boolean openOnly) {
        try {

            IWorkbenchWindow ww = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
            if (ww == null)
                return null;

            IWorkbenchPage page = ww.getActivePage();
            IWorkbenchPart currentPart = page.getActivePart();

            // Checking if view is already open
            IViewReference[] viewRefs = page.getViewReferences();
            for (int i = 0; i < viewRefs.length; i++) {
                IViewReference reference = viewRefs[i];
                String id = reference.getId();
                if (id.equalsIgnoreCase(MainView.ID)) {
                    // Found, restoring the view
                    IViewPart viewPart = reference.getView(true);
                    if (!openOnly)
                        page.activate(viewPart);
                    return (MainView) viewPart;
                }
            }

            // View was not found, opening it up as a new view.
            MainView mView = (MainView) page.showView(MainView.ID);
            if (openOnly)
                page.bringToTop(currentPart);
            return mView;

        } catch (Exception e) {
            e.printStackTrace();

            return null;
        }
    }
}