org.eclipse.ice.client.widgets.ICEResourceView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ice.client.widgets.ICEResourceView.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2014- UT-Battelle, LLC.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Initial API and implementation and/or initial documentation - Jay Jay Billings,
 *   Jordan H. Deyton, Dasha Gorin, Alexander J. McCaskey, Taylor Patterson,
 *   Claire Saunders, Matthew Wang, Anna Wojtowicz
 *******************************************************************************/
package org.eclipse.ice.client.widgets;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

import org.eclipse.ice.client.common.PropertySource;
import org.eclipse.ice.datastructures.ICEObject.Component;
import org.eclipse.ice.datastructures.ICEObject.IUpdateable;
import org.eclipse.ice.datastructures.ICEObject.IUpdateableListener;
import org.eclipse.ice.datastructures.ICEObject.ListComponent;
import org.eclipse.ice.datastructures.componentVisitor.IComponentVisitor;
import org.eclipse.ice.datastructures.componentVisitor.SelectiveComponentVisitor;
import org.eclipse.ice.datastructures.form.Form;
import org.eclipse.ice.datastructures.form.ResourceComponent;
import org.eclipse.ice.datastructures.resource.ICEResource;
import org.eclipse.ice.datastructures.resource.VizResource;
import org.eclipse.jface.action.IToolBarManager;
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.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IPartService;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ca.odell.glazedlists.swt.DefaultEventTableViewer;

/**
 * This class is a ViewPart that creates a tree of text files and a tree of
 * image files collected as ICEResourceComponents.
 * 
 * @author Jay Jay Billings
 * @author Taylor Patterson
 * @author Jordan Deyton
 * @author Anna Wojtowicz
 */
public class ICEResourceView extends PlayableViewPart
        implements IUpdateableListener, IPartListener2, IDoubleClickListener {

    /**
     * Logger for handling event messages and other information.
     */
    private static final Logger logger = LoggerFactory.getLogger(ICEResourceView.class);

    // The ID
    public static final String ID = "org.eclipse.ice.client.widgets.ICEResourceView";

    // ---- Current Editor and Resources ---- //
    /**
     * The currently active ICEFormEditor. This should only be set by the
     * IPartListener2 methods.
     */
    private ICEFormEditor editor;

    /**
     * The ResourceComponent managed by this view. This changes based on the
     * currently active ICEFormEditor.
     * <p>
     * When the ResourceComponent is set or updated, the contents of the view
     * should also update accordingly.
     * </p>
     */
    private ResourceComponent resourceComponent;

    /**
     * The ICEResourcePage managed by this view. This changes based on the
     * currently active ICEFormEditor. This page should also refer to the same
     * ResourceComponent used by this view.
     */
    private ICEResourcePage resourcePage;

    // -------------------------------------- //

    /**
     * The TreeViewer for files in the ResourceComponent.
     */
    private TreeViewer fileTreeViewer;

    /**
     * The TreeViewer for images in the ResourceComponent.
     */
    private TreeViewer imageTreeViewer;

    /**
     * The TabFolder for managing the tabs containing the TreeViewer.
     */
    private TabFolder tabFolder;

    /**
     * Data structure for text-based resources.
     */
    private final List<ResourcePropertySource> textList;

    /**
     * Data structure for image-based resources.
     */
    private final List<ResourcePropertySource> imageList;

    /**
     * Mapping of children in the resource tree to their parent resource.
     */
    private final Map<String, ICEResource> resourceChildMap;

    /**
     * The previous button in the tool bar.
     */
    private PreviousAction prevAction;

    /**
     * The play button in the tool bar.
     */
    private PlayAction playAction;

    /**
     * The next button in the tool bar.
     * </p>
     */
    private NextAction nextAction;

    /**
     * The list of VizResources that should be displayed as plots
     */
    private final ListComponent<VizResource> plotList;

    /**
     * The default constructor.
     */
    public ICEResourceView() {

        // Initialize the lists of property sources.
        textList = new ArrayList<ResourcePropertySource>();
        imageList = new ArrayList<ResourcePropertySource>();

        // Initialize the map of TreeView element names to their ICEResources.
        resourceChildMap = new Hashtable<String, ICEResource>();

        // Initialize the list of VizResources.
        plotList = new ListComponent<VizResource>();

        return;
    }

    /**
     * Sets the currently active {@link #editor}. This triggers any necessary
     * updates to the UI asynchronously.
     * <p>
     * <b>Note:</b> This method should only be called when the active editor
     * changes, e.g., via the {@link IPartListener2} implementation in this
     * class.
     * </p>
     * 
     * @param activeEditor
     *            The new editor, or null to unset it. This is assumed to be a
     *            new value.
     */
    private void setActiveEditor(ICEFormEditor activeEditor) {

        // If necessary, clear the contents of the view.
        if (editor != null) {
            // Clear the ResourceComponent and related UI pieces.
            setResourceComponent(null);
            // Unset the reference to the ICEResourcePage.
            resourcePage = null;
            // Unset the reference to the active editor.
            editor = null;
        }

        // If the new active editor is valid, update the contents of the view.
        if (activeEditor != null) {

            // ---- Determine the ResourceComponent from the editor ---- //
            // Create a visitor to used to find a ResourceComponent.
            final AtomicReference<ResourceComponent> componentRef;
            componentRef = new AtomicReference<ResourceComponent>();
            IComponentVisitor visitor = new SelectiveComponentVisitor() {
                @Override
                public void visit(ResourceComponent component) {
                    componentRef.set(component);
                }
            };

            // Loop over the Form Components to find a ResourceComponent.
            Form activeForm = ((ICEFormInput) activeEditor.getEditorInput()).getForm();
            for (Component i : activeForm.getComponents()) {
                i.accept(visitor);
                // Exit the loop when the first ResourceComponent is found.
                if (componentRef.get() != null) {
                    break;
                }
            }
            // --------------------------------------------------------- //

            // If a ResourceComponent was found, update the known
            // ResourceComponent.
            if (componentRef.get() != null) {
                setResourceComponent(componentRef.get());
            }

            // Set the reference to the new active editor and its resource page.
            editor = activeEditor;
            resourcePage = editor.getResourcePage();
        }

        return;
    }

    /**
     * Sets the current {@link #resourceComponent}. This triggers any updates to
     * the UI asynchronously.
     * <p>
     * <b>Note:</b> This method should only be called when the active
     * {@link #editor} changes, i.e., via
     * {@link #setActiveEditor(ICEFormEditor)}.
     * </p>
     * 
     * @param component
     *            The new ResourceComponent, or null to unset it. This is
     *            assumed to be a new value.
     */
    private void setResourceComponent(ResourceComponent component) {

        // If necessary, clear the contents of the view and unregister from the
        // previous ResourceComponent.
        if (resourceComponent != null) {
            // Unregister from the old ResourceComponent.
            resourceComponent.unregister(this);

            // Clear the related UI pieces.
            if (fileTreeViewer != null && !fileTreeViewer.getControl().isDisposed()) {
                textList.clear();
                fileTreeViewer.refresh();
                fileTreeViewer.getTree().redraw();
            }

            // Clear the related UI pieces.
            if (imageTreeViewer != null && !imageTreeViewer.getControl().isDisposed()) {
                imageList.clear();
                imageTreeViewer.refresh();
                imageTreeViewer.getTree().redraw();
            }

            // Unset the reference to the old ResourceComponent.
            resourceComponent = null;
        }

        // If the new ResourceComponent is valid, update the contents of the
        // view and register for updates from it.
        if (component != null) {
            // Set the component reference
            resourceComponent = component;
            // Register this view with the Component to receive updates
            resourceComponent.register(this);
            // Trigger a UI update.
            update(resourceComponent);
        }

        return;
    }

    /**
     * This operation retrieves the ResourceComponent that has been rendered by
     * the ICEResourceView or null if the component does not exist.
     * 
     * @return The ResourceComponent or null if the component was not previously
     *         set.
     */
    public ResourceComponent getResourceComponent() {
        return resourceComponent;
    }

    /**
     * This operation overrides the ViewPart.createPartControl method to create
     * and draw the TreeViewer before registering it as a selection provider.
     * 
     * @param parent
     *            The Composite used to create the TreeViewer.
     */
    @Override
    public void createPartControl(Composite parent) {

        // Create a TabFolder to manage tabs
        tabFolder = new TabFolder(parent, SWT.NONE);

        // Create pages (TabItems) for text files and images
        TabItem textTab = new TabItem(tabFolder, SWT.NONE, 0);
        textTab.setText("Files");
        TabItem imageTab = new TabItem(tabFolder, SWT.NONE, 1);
        imageTab.setText("Images");
        TabItem plotTab = new TabItem(tabFolder, SWT.NONE, 2);
        plotTab.setText("Plots");

        // Create the tool bar and buttons for the view
        createActions();

        // Initialize the TreeViewer
        fileTreeViewer = new TreeViewer(tabFolder);
        imageTreeViewer = new TreeViewer(tabFolder);
        // Create content and label providers
        initializeTreeViewer(fileTreeViewer);
        initializeTreeViewer(imageTreeViewer);
        // Register the tree to the tabs
        textTab.setControl(fileTreeViewer.getControl());
        imageTab.setControl(imageTreeViewer.getControl());
        // Register this view as a SelectionProvider
        getSite().setSelectionProvider(fileTreeViewer);
        getSite().setSelectionProvider(imageTreeViewer);
        // Registered the view as a double click listener of the TreeViewer
        fileTreeViewer.addDoubleClickListener(this);
        imageTreeViewer.addDoubleClickListener(this);

        // Add a listener to catch tab selection changes.
        // NOTE: In Windows, this event is fired instantly, so this listener
        // needs to be declared after everything else is initialized!
        tabFolder.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {
                // If tabs are changed while playing, stop playing.
                if (playAction.isInPlayState()) {
                    playAction.stop();
                }
                // Set the TreeViewer input to the selected tab
                setTreeContent(tabFolder.indexOf((TabItem) event.item));
            }
        });

        // Create the Table and table viewer for the Plot tab
        Table listTable = new Table(tabFolder, SWT.FLAT);
        DefaultEventTableViewer<VizResource> listTableViewer = new DefaultEventTableViewer<VizResource>(plotList,
                listTable, plotList);
        // Register the table control with the plot tab
        plotTab.setControl(listTable);

        // Check if there is currently an active ICEFormEditor. If so, update
        // the currently active editor and related UI pieces.
        IEditorPart activeEditor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
                .getActiveEditor();
        if (activeEditor != null && activeEditor instanceof ICEFormEditor) {
            if (activeEditor != editor) {
                setActiveEditor((ICEFormEditor) activeEditor);
            }
        } else {
            // Get a list of all the currently open editors
            IWorkbenchPage workbenchPage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
            IEditorReference[] editorRefs = workbenchPage.getEditorReferences();

            if (editorRefs != null && editorRefs.length > 0) {
                // Begin iterating through all the editors, looking for one
                // that's an ICEFormEditor
                for (IEditorReference e : editorRefs) {
                    // If it's an ICEFormEditor, set it as the active editor
                    if (e.getId().equals(ICEFormEditor.ID)) {
                        setActiveEditor((ICEFormEditor) e.getEditor(false));
                        break;
                    }
                }
            }
        }

        // Register as a listener to the part service so that the view can
        // update when the active ICEFormEditor changes.
        IPartService partService = getSite().getWorkbenchWindow().getPartService();
        partService.addPartListener(this);

        return;
    }

    /**
     * This operation creates content and label providers for a TreeViewer.
     * 
     * @param inputTreeViewer
     *            The TreeViewer to have the providers added to.
     */
    private void initializeTreeViewer(TreeViewer inputTreeViewer) {

        // Create a content provider that will show the name and its path and
        // edit date as children
        inputTreeViewer.setContentProvider(new ITreeContentProvider() {

            @Override
            public void dispose() {
            }

            @Override
            public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
                // Don't handle input changes
                return;
            }

            @Override
            public Object[] getElements(Object inputElement) {
                // Cast the input and return it as an array
                return ((List<?>) inputElement).toArray();
            }

            @Override
            public Object[] getChildren(Object parentElement) {
                // If the element is a PropertySource
                if (parentElement instanceof PropertySource) {
                    PropertySource source = (PropertySource) parentElement;
                    ICEResource resource = (ICEResource) source.getWrappedData();
                    // Load the path and modification date as children
                    String[] children = { "Path: " + resource.getPath().toASCIIString(),
                            "Date: " + resource.getLastModificationDate() };

                    // Map the children to their parent resource for appropriate
                    // selection behavior
                    resourceChildMap.put("Path: " + resource.getPath().toASCIIString(), resource);
                    resourceChildMap.put("Date: " + resource.getLastModificationDate(), resource);

                    return children;
                }
                return null;
            }

            @Override
            public Object getParent(Object element) {
                // Don't identify parents
                return null;
            }

            @Override
            public boolean hasChildren(Object element) {
                // Only PropertySources will have children
                if (element instanceof PropertySource) {
                    return true;
                }
                return false;
            }

        });
        // Add a label provider to properly label the resources
        inputTreeViewer.setLabelProvider(new LabelProvider() {
            @Override
            public String getText(Object element) {
                // Only set a label if it is an ICEResource. Otherwise we
                // shouldn't need it.... I think.
                if (element instanceof PropertySource) {
                    PropertySource source = (PropertySource) element;
                    ICEResource resource = (ICEResource) source.getWrappedData();
                    return resource.getName();
                }
                return (String) element;
            }

            @Override
            public Image getImage(Object element) {
                // If it is a resource, set a "folder" picture
                if (element instanceof PropertySource) {
                    return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
                }
                return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE);
            }

        });

        return;
    }

    /**
     * This method listens for a double click event on a resource. If the
     * selected resource is valid, then it will be displayed on the view's
     * associated {@link ICEResourceView#resourcePage}.
     */
    @Override
    public void doubleClick(DoubleClickEvent event) {

        // Get the associated resource
        ISelection selection = event.getSelection();
        ICEResource selectedResource = getResourceFromSelection(selection);

        // If it's valid, try to display it on the ResourcePage
        if (selectedResource != null) {
            try {
                resourcePage.getEditor().setActivePage(resourcePage.getId());
                resourcePage.showResource(selectedResource);
            } catch (PartInitException e) {
                logger.error(getClass().getName() + " Exception!", e);
            }
        }

        return;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
     */
    @Override
    public void setFocus() {
        // Do nothing
    }

    /**
     * Update resourceTreeViewer when a new resource becomes available.
     * 
     * @see IUpdateableListener#update(IUpdateable)
     */
    @Override
    public void update(IUpdateable component) {

        // Only perform a UI update if the component is valid and the UI pieces
        // exist.
        if (component != null && component == resourceComponent && fileTreeViewer != null) {

            // Sync with the display
            PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
                @Override
                public void run() {
                    // Just do a blanket update - no need to check the component
                    if (fileTreeViewer != null && !fileTreeViewer.getControl().isDisposed()) {
                        logger.info("ICEResourceView Message: " + "Updating resource table.");
                        sortTreeContent();
                        setTreeContent();
                        fileTreeViewer.refresh();
                        fileTreeViewer.getTree().redraw();
                    }
                }
            });
        }

        // Only perform a UI update if the component is valid and the UI
        // pieces exist.
        if (component != null && component == resourceComponent && imageTreeViewer != null) {

            // Sync with the display
            PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
                @Override
                public void run() {
                    // Just do a blanket update - no need to check the
                    // component
                    if (imageTreeViewer != null && !imageTreeViewer.getControl().isDisposed()) {
                        logger.info("ICEResourceView Message: " + "Updating resource table.");
                        sortTreeContent();
                        setTreeContent();
                        imageTreeViewer.refresh();
                        imageTreeViewer.getTree().redraw();
                    }
                }
            });
        }

        return;
    }

    /**
     * This operation populates the ArrayLists for text- and image-based
     * resources.
     */
    private void sortTreeContent() {

        // Ensure a non-null resourceComponent
        if (resourceComponent != null) {
            // Remove the current list contents
            textList.clear();
            imageList.clear();

            // Re-populate the resource lists
            for (ICEResource i : resourceComponent.getResources()) {
                if (!i.isPictureType()) {
                    textList.add(new ResourcePropertySource(i));
                } else if (i.isPictureType()) {
                    imageList.add(new ResourcePropertySource(i));
                } else {
                    logger.info("ERROR: Unknown resource type.");
                }
            }
        }

        return;
    }

    /**
     * This operation sets the input of the resourceTreeViewer.
     */
    private void setTreeContent() {

        // If currently playing, stop.
        if (playAction.isInPlayState()) {
            playAction.stop();
        }

        imageTreeViewer.setInput(imageList);
        fileTreeViewer.setInput(textList);

        // If there are no files, but there are images, set to the images tab.
        // Otherwise, default to the files tab.
        if (textList.isEmpty() && !imageList.isEmpty()) {
            tabFolder.setSelection(1);
            playable = true;

            // Select the first available image resource.
            imageTreeViewer.setSelection(new StructuredSelection(imageList.get(0)), true);
        } else {
            tabFolder.setSelection(0);
            playable = false;

            // Select the first available text resource.
            if (!textList.isEmpty()) {
                fileTreeViewer.setSelection(new StructuredSelection(textList.get(0)), true);
            }
        }

        return;
    }

    /**
     * This operation sets the input of the resourceTreeViewer when a tab
     * selection change occurs.
     * 
     * @param tabIndex
     *            The currently selected tab.
     */
    private void setTreeContent(int tabIndex) {

        // If currently playing, stop.
        if (playAction.isInPlayState()) {
            playAction.stop();
        }

        // Set the tree content
        imageTreeViewer.setInput(imageList);
        fileTreeViewer.setInput(textList);

        // Check if the new content is playable
        if (tabIndex == 1) {
            if (!imageList.isEmpty()) {
                playable = true;
            }
        } else {
            playable = false;
        }
        return;
    }

    // ---- Implements IPartListener2 ---- //
    // This class implements IPartListener2 in order to synchronize with the
    // currently active ICEFormEditor. When an ICEFormEditor is activated, this
    // view looks for the editor's ResourceComponents and lists all of their
    // ICEResources in the TreeViewer. When the currently activated
    // ICEFormEditor is closed, then the view should clear.

    /**
     * This function is called whenever a Workbench part gains focus. Here, we
     * are only interested if the part is an ICEFormEditor. When a new
     * ICEFormEditor is activated, sync the view with the activated editor.
     */
    @Override
    public void partActivated(IWorkbenchPartReference partRef) {

        // If the activated editor is an ICEFormEditor different from the known
        // active ICEFormEditor, call the method to update the currently active
        // editor and affected UI pieces.
        IWorkbenchPart part = partRef.getPart(false);
        if (part != null && part instanceof ICEFormEditor) {
            ICEFormEditor activeEditor = (ICEFormEditor) part;
            if (activeEditor != editor) {
                setActiveEditor(activeEditor);
            }
        }

        return;
    }

    /**
     * This function is called whenever a Workbench part is closed. If the
     * current {@link #editor} is closed, then we need to clear the view's
     * contents.
     */
    @Override
    public void partClosed(IWorkbenchPartReference partRef) {

        // If the closed editor is the known active ICEFormEditor, call the
        // method to clear the currently active editor and related UI pieces.
        IWorkbenchPart part = partRef.getPart(false);
        if (part != null && part instanceof ICEFormEditor) {
            ICEFormEditor activeEditor = (ICEFormEditor) partRef.getPart(false);
            if (activeEditor == editor) {
                setActiveEditor(null);
            }
        }

        return;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IPartListener2#partHidden(org.eclipse.ui.
     * IWorkbenchPartReference)
     */
    @Override
    public void partHidden(IWorkbenchPartReference partRef) {
        // Do nothing.
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IPartListener2#partBroughtToTop(org.eclipse.ui.
     * IWorkbenchPartReference)
     */
    @Override
    public void partBroughtToTop(IWorkbenchPartReference partRef) {
        // Do nothing.
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IPartListener2#partDeactivated(org.eclipse.ui.
     * IWorkbenchPartReference)
     */
    @Override
    public void partDeactivated(IWorkbenchPartReference partRef) {
        // Do nothing.
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IPartListener2#partOpened(org.eclipse.ui.
     * IWorkbenchPartReference)
     */
    @Override
    public void partOpened(IWorkbenchPartReference partRef) {
        // Do nothing.
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui.
     * IWorkbenchPartReference)
     */
    @Override
    public void partVisible(IWorkbenchPartReference partRef) {
        // Do nothing.
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IPartListener2#partInputChanged(org.eclipse.ui.
     * IWorkbenchPartReference)
     */
    @Override
    public void partInputChanged(IWorkbenchPartReference partRef) {
        // Do nothing.
    }

    // ----------------------------------- //

    /**
     * Attempts to determine the {@link ICEResource} from the selection. The
     * selection is assumed to be from this view, and so its selection structure
     * applies.
     * 
     * @param selection
     *            The selection to convert.
     * @return The Resource from the selection, or null if the selection was
     *         invalid.
     */
    public ICEResource getResourceFromSelection(ISelection selection) {
        ICEResource selectedResource = null;
        if (selection != null && !selection.isEmpty() && selection instanceof IStructuredSelection) {
            Object element = ((IStructuredSelection) selection).getFirstElement();
            // Strings must be looked up in the Resource View's map.
            if (element instanceof String) {
                selectedResource = resourceChildMap.get(element);
            }
            // PropertySources should wrap ICEResources.
            else if (element instanceof PropertySource) {
                PropertySource source = (PropertySource) element;
                selectedResource = (ICEResource) source.getWrappedData();
            }
        }
        return selectedResource;
    }

    /**
     * Create and add the play, previous, and next buttons to the tool bar for
     * this view.
     */
    private void createActions() {

        // Get the IToolBarManager
        IActionBars actionBars = getViewSite().getActionBars();
        IToolBarManager toolBarManager = actionBars.getToolBarManager();

        // Create a previous button and add it to the tool bar
        prevAction = new PreviousAction(this);
        toolBarManager.add(prevAction);

        // Create a play button and add it to the tool bar
        playAction = new PlayAction(this);
        toolBarManager.add(playAction);

        // Create a next button and add it to the tool bar
        nextAction = new NextAction(this);
        toolBarManager.add(nextAction);

        return;
    }

    /**
     * Set the resourceTreeViewer selection to the next item (file or image) in
     * the currently displayed resource list. If current selection is the last
     * item in the list, cycle to the front of the list.
     * 
     * @see PlayableViewPart#setToNextResource()
     */
    @Override
    public void setToNextResource() {

        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
            @Override
            public void run() {
                // Get the currently selected resource in the view. (Or the
                // first selected resource if multiple resources are
                // selected even though this has no effect.)
                TreeItem[] currSelection;
                int currIndex;

                // Set the selection to the next resource in the currently
                // displayed list or the first resource if the last resource
                // is currently selected.
                if (tabFolder.getSelectionIndex() == 1 && !imageList.isEmpty()) {
                    currSelection = imageTreeViewer.getTree().getSelection();
                    currIndex = imageTreeViewer.getTree().indexOf(currSelection[0]);

                    int nextIndex = (currIndex + 1) % imageList.size();
                    imageTreeViewer.setSelection(new StructuredSelection(imageList.get(nextIndex)), true);
                } else if (!textList.isEmpty()) {
                    currSelection = fileTreeViewer.getTree().getSelection();
                    currIndex = fileTreeViewer.getTree().indexOf(currSelection[0]);

                    int nextIndex = (currIndex + 1) % textList.size();
                    fileTreeViewer.setSelection(new StructuredSelection(textList.get(nextIndex)), true);
                }
            }
        });

        return;
    }

    /**
     * Set the resourceTreeViewer selection to the previous item (file or image)
     * in the currently displayed resource list. If current selection is the
     * first item in the list, cycle to the back of the list.
     * 
     * @see PlayableViewPart#setToPreviousResource()
     */
    @Override
    public void setToPreviousResource() {

        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
            @Override
            public void run() {
                // Get the currently selected resource in the view. (Or the
                // first selected resource if multiple resources are
                // selected even though this has no effect.)
                TreeItem[] currSelection;
                int currIndex;

                // Set the selection to the previous resource in the
                // currently displayed list, or the last resource if the first
                // resource is currently selected.
                if (tabFolder.getSelectionIndex() == 1 && !imageList.isEmpty()) {
                    currSelection = imageTreeViewer.getTree().getSelection();
                    currIndex = imageTreeViewer.getTree().indexOf(currSelection[0]);

                    int prevIndex = (currIndex - 1) % imageList.size();
                    if (prevIndex < 0) {
                        prevIndex = imageList.size() - 1;
                    }
                    imageTreeViewer.setSelection(new StructuredSelection(imageList.get(prevIndex)), true);
                } else if (!textList.isEmpty()) {
                    currSelection = fileTreeViewer.getTree().getSelection();
                    currIndex = fileTreeViewer.getTree().indexOf(currSelection[0]);

                    int prevIndex = (currIndex - 1) % textList.size();
                    if (prevIndex < 0) {
                        prevIndex = textList.size() - 1;
                    }
                    fileTreeViewer.setSelection(new StructuredSelection(textList.get(prevIndex)), true);
                }
            }
        });

        return;
    }

    /**
     * A private subclass of PropertySource to implement the superclass features
     * used by ICEResourceView.
     */
    private static class ResourcePropertySource extends PropertySource {

        // Property IDs
        public static final String ID_PATH = "Path";
        public static final String ID_DATE = "Date";

        // IPropertyDescriptors for the class
        protected static IPropertyDescriptor[] descriptors;

        static {
            descriptors = new IPropertyDescriptor[] { new PropertyDescriptor(ID_PATH, "Path"),
                    new PropertyDescriptor(ID_DATE, "Date") };
        }

        /**
         * The constructor
         * 
         * @param obj
         *            The object to be wrapped by PropertySource. For this
         *            subclass, this will be an ICEResource.
         */
        public ResourcePropertySource(Object obj) {

            // Just call the superclass constructor
            super(obj);

            return;
        }

        /**
         * This function returns the array of descriptors for properties.
         * 
         * @return The array of descriptors for properties.
         * 
         * @see IPropertySource#getPropertyDescriptors()
         */
        @Override
        public IPropertyDescriptor[] getPropertyDescriptors() {
            return descriptors;
        }

        /**
         * This function returns the value for a give property.
         * 
         * @param id
         *            The object used to identify this property.
         * @return The value for the input property
         * 
         * @see IPropertySource#getPropertyValue(Object)
         */
        @Override
        public Object getPropertyValue(Object id) {

            // If the caller seeks the path property, get it from the wrapped
            // resource and return it.
            if (ID_PATH.equals(id)) {
                ICEResource resource = (ICEResource) this.getWrappedData();
                return resource.getPath().toASCIIString();
            }
            // If the caller seeks the date property, get it from the wrapped
            // resource and return it.
            else if (ID_DATE.equals(id)) {
                ICEResource resource = (ICEResource) this.getWrappedData();
                return resource.getLastModificationDate();
            }
            // Otherwise, the property is unknown.
            else {
                return super.getPropertyValue(id);
            }
        }
    }
}